From a6d95bf39951c9033d7abac3c3a580b54d1917b0 Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Wed, 6 Mar 2013 19:39:56 +0100 Subject: Piranha (P5100/P3100 Galaxy Tab 2.0 tablets) support Change-Id: Ie3d120723aeff044d127ff66e46ec9e7b5f476cc Signed-off-by: Paul Kocialkowski --- Android.mk | 24 +- samsung-ipc/device/piranha/piranha_ipc.c | 57 +++ samsung-ipc/device/piranha/piranha_loader.c | 766 ++++++++++++++++++++++++++++ samsung-ipc/device/piranha/piranha_loader.h | 90 ++++ samsung-ipc/ipc_devices.c | 20 + samsung-ipc/ipc_devices.h | 7 + 6 files changed, 963 insertions(+), 1 deletion(-) create mode 100644 samsung-ipc/device/piranha/piranha_ipc.c create mode 100644 samsung-ipc/device/piranha/piranha_loader.c create mode 100644 samsung-ipc/device/piranha/piranha_loader.h diff --git a/Android.mk b/Android.mk index 8955c3c..85f70f3 100644 --- a/Android.mk +++ b/Android.mk @@ -45,6 +45,16 @@ ifeq ($(TARGET_DEVICE),maguro) board_name := tuna endif +ifeq ($(TARGET_DEVICE),p5100) + LOCAL_CFLAGS += -DDEVICE_IPC_V4 + board_name := espresso10 +endif + +ifeq ($(TARGET_DEVICE),p3100) + LOCAL_CFLAGS += -DDEVICE_IPC_V4 + board_name := espresso +endif + ifeq ($(DEBUG),true) LOCAL_CFLAGS += -DDEBUG LOCAL_CFLAGS += -DLOG_STDOUT @@ -71,7 +81,9 @@ samsung-ipc_files := \ samsung-ipc/device/galaxys2/galaxys2_loader.c \ samsung-ipc/device/galaxys2/galaxys2_ipc.c \ samsung-ipc/device/maguro/maguro_loader.c \ - samsung-ipc/device/maguro/maguro_ipc.c + samsung-ipc/device/maguro/maguro_ipc.c \ + samsung-ipc/device/piranha/piranha_loader.c \ + samsung-ipc/device/piranha/piranha_ipc.c LOCAL_SRC_FILES := $(samsung-ipc_files) LOCAL_CFLAGS += -DIPC_BOARD_NAME_EXPLICIT=\"$(board_name)\" @@ -123,6 +135,16 @@ ifeq ($(TARGET_DEVICE),maguro) samsung-ipc_device := maguro endif +ifeq ($(TARGET_DEVICE),p5100) + LOCAL_CFLAGS += -DDEVICE_IPC_V4 + samsung-ipc_device := espresso10 +endif + +ifeq ($(TARGET_DEVICE),p3100) + LOCAL_CFLAGS += -DDEVICE_IPC_V4 + samsung-ipc_device := espresso +endif + ifeq ($(DEBUG),true) LOCAL_CFLAGS += -DDEBUG LOCAL_CFLAGS += -DLOG_STDOUT diff --git a/samsung-ipc/device/piranha/piranha_ipc.c b/samsung-ipc/device/piranha/piranha_ipc.c new file mode 100644 index 0000000..0277ec3 --- /dev/null +++ b/samsung-ipc/device/piranha/piranha_ipc.c @@ -0,0 +1,57 @@ +/** + * This file is part of libsamsung-ipc. + * + * Copyright (C) 2013 Paul Kocialkowski + * + * libsamsung-ipc 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. + * + * libsamsung-ipc 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 libsamsung-ipc. If not, see . + */ + +#include + +#include "ipc_private.h" + +#include "xmm6260_ipc.h" +#include "piranha_loader.h" + +struct ipc_ops piranha_fmt_ops = { + .send = xmm6260_ipc_fmt_client_send, + .recv = xmm6260_ipc_fmt_client_recv, + .bootstrap = piranha_modem_bootstrap, +}; + +struct ipc_ops piranha_rfs_ops = { + .send = xmm6260_ipc_rfs_client_send, + .recv = xmm6260_ipc_rfs_client_recv, + .bootstrap = NULL, +}; + +struct ipc_handlers piranha_default_handlers = { + .read = xmm6260_ipc_read, + .write = xmm6260_ipc_write, + .open = xmm6260_ipc_open, + .close = xmm6260_ipc_close, + .power_on = xmm6260_ipc_power_on, + .power_off = xmm6260_ipc_power_off, + .common_data = NULL, + .common_data_create = xmm6260_ipc_common_data_create, + .common_data_destroy = xmm6260_ipc_common_data_destroy, + .common_data_set_fd = xmm6260_ipc_common_data_set_fd, + .common_data_get_fd = xmm6260_ipc_common_data_get_fd, +}; + +struct ipc_gprs_specs piranha_gprs_specs = { + .gprs_get_iface = xmm6260_ipc_gprs_get_iface, + .gprs_get_capabilities = xmm6260_ipc_gprs_get_capabilities, +}; + diff --git a/samsung-ipc/device/piranha/piranha_loader.c b/samsung-ipc/device/piranha/piranha_loader.c new file mode 100644 index 0000000..7244d49 --- /dev/null +++ b/samsung-ipc/device/piranha/piranha_loader.c @@ -0,0 +1,766 @@ +/* + * Copyright (C) 2013 Paul Kocialkowski + * Copyright (C) 2012 Alexander Tarasikov + * + * based on the incomplete C++ implementation which is + * Copyright (C) 2012 Sergey Gridasov + * + * 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, see . + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +//for timeval +#include + +//for mmap +#include +#include + +#include "ipc_private.h" + +#include "xmm6260_loader.h" +#include "xmm6260_modemctl.h" + +#include "piranha_loader.h" + +// TODO: redo log messages + +struct piranha_radio_part piranha_radio_parts[] = { + { + .id = PSI, + .offset = 0x1000, + .length = 0xe000, + }, + { + .id = EBL, + .offset = 0xf000, + .length = 0x19000, + }, + { + .id = SECURE_IMAGE, + .offset = 0x9ff800, + .length = 0x800, + }, + { + .id = FIRMWARE, + .offset = 0x28000, + .length = 0x9d7800, + }, + { + .id = NVDATA, + .offset = 0xa00000, + .length = 2 << 20, + }, +}; + +int piranha_radio_parts_count = sizeof(piranha_radio_parts) / sizeof(struct piranha_radio_part); + +struct piranha_boot_cmd piranha_boot_cmds[] = { + { + .cmd = SetPortConf, + .code = 0x86, + .flags = PIRANHA_FLAG_NONE, + }, + { + .cmd = ReqSecStart, + .code = 0x204, + .flags = PIRANHA_FLAG_NONE, + }, + { + .cmd = ReqSecEnd, + .code = 0x205, + .flags = PIRANHA_FLAG_SHORT_TAIL, + }, + { + .cmd = ReqForceHwReset, + .code = 0x208, + .flags = PIRANHA_FLAG_NO_ACK, + }, + { + .cmd = ReqFlashSetAddress, + .code = 0x802, + .flags = PIRANHA_FLAG_NONE, + }, + { + .cmd = ReqFlashWriteBlock, + .code = 0x804, + .flags = PIRANHA_FLAG_SHORT_TAIL, + }, +}; + +int piranha_boot_cmds_count = sizeof(piranha_boot_cmds) / sizeof(struct piranha_boot_cmd); + +struct piranha_radio_part *piranha_radio_part_get(int id) +{ + int i; + + for (i=0 ; i < piranha_radio_parts_count ; i++) { + if (piranha_radio_parts[i].id == id) + return &piranha_radio_parts[i]; + } + + return NULL; +} + +struct piranha_boot_cmd *piranha_boot_cmd_get(int cmd) +{ + int i; + + for (i=0 ; i < piranha_boot_cmds_count ; i++) { + if (piranha_boot_cmds[i].cmd == cmd) + return &piranha_boot_cmds[i]; + } + + return NULL; +} + +int piranha_ack_read(struct ipc_client *client, int fd, int ack) +{ + int c, v; + int rc; + + v = 0; + for (c=0 ; c < 10 ; c++) { + rc = expect_read(fd, &v, sizeof(v)); + if ((v & 0xffff) == ack) + break; + } + + if (rc <= 0 || (v & 0xffff) != ack) + return -1; + + return 0; +} + +void piranha_boot_cmd_header_fill(struct piranha_boot_cmd_header *header, + uint16_t code, int size) +{ + memset(header, 0, sizeof(struct piranha_boot_cmd_header)); + header->size = size + sizeof(struct piranha_boot_cmd_header); + header->magic = PIRANHA_MAGIC_BOOT_CMD_HEADER; + header->code = code; + header->data_size = size; +} + +void piranha_boot_cmd_tail_fill(struct piranha_boot_cmd_tail *tail, + uint16_t code, void *data, int size) +{ + unsigned char *p = NULL; + int i; + + memset(tail, 0, sizeof(struct piranha_boot_cmd_tail)); + tail->checksum = (size & 0xffff) + code; + tail->magic = PIRANHA_MAGIC_BOOT_CMD_TAIL; + tail->unknown = PIRANHA_MAGIC_BOOT_CMD_UNKNOWN; + + p = data; + + for (i=0 ; i < size ; i++) + tail->checksum += *p++; +} + +int piranha_boot_cmd_send(struct ipc_client *client, struct modemctl_io_data *io_data, + int cmd, void *data, int size) +{ + struct piranha_boot_cmd *boot_cmd; + struct piranha_boot_cmd_header *header_p; + unsigned char *p; + + struct piranha_boot_cmd_header header; + struct piranha_boot_cmd_tail tail; + int tail_length; + + void *cmd_data = NULL; + int cmd_length = 0; + + void *ack_data = NULL; + int ack_length = 0; + + int count, length; + int chunk = 4; + + int rc; + + boot_cmd = piranha_boot_cmd_get(cmd); + if (boot_cmd == NULL) + goto fail; + + piranha_boot_cmd_header_fill(&header, boot_cmd->code, size); + piranha_boot_cmd_tail_fill(&tail, boot_cmd->code, data, size); + + tail_length = sizeof(tail); + if (boot_cmd->flags & PIRANHA_FLAG_SHORT_TAIL) + tail_length -= 2; + + cmd_length = sizeof(header) + size + tail_length; + cmd_data = calloc(1, cmd_length); + + p = (unsigned char *) cmd_data; + memcpy(p, &header, sizeof(header)); + p += sizeof(header); + memcpy(p, data, size); + p += size; + memcpy(p, &tail, tail_length); + + rc = write(io_data->boot_fd, cmd_data, cmd_length); + if (rc != cmd_length) + goto fail; + + if (boot_cmd->flags & PIRANHA_FLAG_NO_ACK) + goto done; + + rc = expect_read(io_data->boot_fd, &ack_length, sizeof(ack_length)); + if (rc != sizeof(ack_length) || ack_length <= 0) + goto fail; + + // Add short tail + ack_length += sizeof(tail) - 2; + if (ack_length % 4 != 0) + ack_length += ack_length % 4; + ack_data = calloc(1, ack_length); + + p = (unsigned char *) ack_data; + memcpy(p, &ack_length, sizeof(ack_length)); + p += sizeof(ack_length); + + length = ack_length; + count = sizeof(ack_length); + + while (count < length) { + rc = expect_read(io_data->boot_fd, p, chunk < length - count ? chunk : length - count); + if (rc < 0) + goto fail; + + p += rc; + count += rc; + } + + header_p = (struct piranha_boot_cmd_header *) ack_data; + if (header_p->code != boot_cmd->code) + goto fail; + + rc = 0; + goto done; + +fail: + rc = -1; + +done: + if (cmd_data != NULL) + free(cmd_data); + if (ack_data != NULL) + free(ack_data); + + return rc; +} + +int piranha_boot_data_send(struct ipc_client *client, struct modemctl_io_data *io_data, + int address, void *data, int length) +{ + unsigned char *p = NULL; + int count; + int chunk = 0xdf2; + int rc; + + rc = piranha_boot_cmd_send(client, io_data, ReqFlashSetAddress, &address, sizeof(address)); + if (rc < 0) + goto fail; + + p = (unsigned char *) data; + count = 0; + + while (count < length) { + rc = piranha_boot_cmd_send(client, io_data, ReqFlashWriteBlock, p, chunk < length - count ? chunk : length - count); + if (rc < 0) + goto fail; + + p += chunk; + count += chunk; + } + + return 0; + +fail: + return -1; +} + +int piranha_sec_send(struct ipc_client *client, struct modemctl_io_data *io_data) +{ + struct piranha_radio_part *radio_part; + void *nv_data = NULL; + + uint16_t sec_end_data; + uint32_t hw_reset_data; + + int length, offset; + void *data; + int start, end; + int rc; + + // SEC start + ipc_client_log(client, "%s: Sending SEC start image", __func__); + + radio_part = piranha_radio_part_get(SECURE_IMAGE); + if (radio_part == NULL) + goto fail; + + length = radio_part->length; + offset = radio_part->offset; + + data = io_data->radio_data + offset; + + rc = piranha_boot_cmd_send(client, io_data, ReqSecStart, data, length); + if (rc < 0) { + ipc_client_log(client, "%s: Failed to send start SEC image", __func__); + goto fail; + } + + // Firmware + ipc_client_log(client, "%s: Sending Firmware image", __func__); + + radio_part = piranha_radio_part_get(FIRMWARE); + if (radio_part == NULL) + goto fail; + + length = radio_part->length; + offset = radio_part->offset; + + data = io_data->radio_data + offset; + + rc = piranha_boot_data_send(client, io_data, PIRANHA_ADDRESS_FIRMWARE, data, length); + if (rc < 0) { + ipc_client_log(client, "%s: Failed to send Firmware image", __func__); + goto fail; + } + + // NV Data + ipc_client_log(client, "%s: Sending NV Data image", __func__); + + rc = nv_data_check(client); + if (rc < 0) + goto fail; + + rc = nv_data_md5_check(client); + if (rc < 0) + goto fail; + + nv_data = ipc_client_file_read(client, nv_data_path(client), 2 << 20, 1024); + if (nv_data == NULL) { + ipc_client_log(client, "%s: Failed to read NV Data image (%s)", __func__, nv_data_path(client)); + goto fail; + } + + rc = piranha_boot_data_send(client, io_data, PIRANHA_ADDRESS_NV_DATA, nv_data, 2 << 20); + if (rc < 0) { + ipc_client_log(client, "%s: Failed to send NV Data image", __func__); + goto fail; + } + + // SEC end + ipc_client_log(client, "%s: Sending SEC end", __func__); + + sec_end_data = PIRANHA_MAGIC_BOOT_CMD_SEC_END; + piranha_boot_cmd_send(client, io_data, ReqSecEnd, &sec_end_data, sizeof(sec_end_data)); + if (rc < 0) { + ipc_client_log(client, "%s: Failed to send SEC end", __func__); + goto fail; + } + + // HW reset + ipc_client_log(client, "%s: Sending HW reset", __func__); + + hw_reset_data = PIRANHA_MAGIC_BOOT_CMD_HW_RESET; + piranha_boot_cmd_send(client, io_data, ReqForceHwReset, &hw_reset_data, sizeof(hw_reset_data)); + if (rc < 0) { + ipc_client_log(client, "%s: Failed to send HW reset", __func__); + goto fail; + } + + rc = 0; + goto done; + +fail: + rc = -1; + +done: + if (nv_data != NULL) + free(nv_data); + + return rc; +} + +int piranha_ebl_set(struct ipc_client *client, struct modemctl_io_data *io_data) +{ + unsigned char *data = NULL; + unsigned char *p = NULL; + int count, length; + int chunk = 4; + int rc; + + rc = expect_read(io_data->boot_fd, &length, sizeof(length)); + if (rc != sizeof(length)) { + ipc_client_log(client, "%s: Failed to read EBL set length", __func__); + goto fail; + } + + data = calloc(1, length); + p = data; + count = 0; + + while (count < length) { + rc = expect_read(io_data->boot_fd, p, chunk < length - count ? chunk : length - count); + if (rc < 0) { + ipc_client_log(client, "%s: Failed to read EBL set data", __func__); + goto fail; + } + + p += rc; + count += rc; + } + + rc = piranha_boot_cmd_send(client, io_data, SetPortConf, data, length); + if (rc < 0) { + ipc_client_log(client, "%s: Failed to send EBL set data", __func__); + goto fail; + } + + return 0; + +fail: + if (data != NULL) + free(data); + + return -1; +} + +int piranha_ebl_send(struct ipc_client *client, struct modemctl_io_data *io_data) +{ + struct piranha_radio_part *radio_part; + int length, offset; + int chunk = 0xdfc; + + int start, end; + unsigned char crc; + + unsigned char *p; + int v; + int rc; + + radio_part = piranha_radio_part_get(EBL); + if (radio_part == NULL) + goto fail; + + length = radio_part->length; + offset = radio_part->offset; + start = offset; + end = start + length; + + v = sizeof(length); + rc = write(io_data->boot_fd, &v, sizeof(v)); + if (rc != sizeof(v)) { + ipc_client_log(client, "%s: Failed to write EBL length length", __func__); + goto fail; + } + + rc = write(io_data->boot_fd, &length, sizeof(length)); + if (rc != sizeof(length)) { + ipc_client_log(client, "%s: Failed to write EBL length (1)", __func__); + goto fail; + } + + rc = piranha_ack_read(client, io_data->boot_fd, PIRANHA_ACK_EBL_LENGTH); + if (rc < 0) { + ipc_client_log(client, "%s: Failed to read EBL length ACK", __func__); + goto fail; + } + + v = length; + p = (unsigned char *) &v; + *p = 1; + + rc = write(io_data->boot_fd, &v, sizeof(v)); + if (rc != sizeof(v)) { + ipc_client_log(client, "%s: Failed to write EBL length (2)", __func__); + goto fail; + } + + while (start < end) { + rc = write(io_data->boot_fd, io_data->radio_data + start, chunk < end - start ? chunk : end - start); + if (rc < 0) { + ipc_client_log(client, "%s: Failed to write EBL data", __func__); + goto fail; + } + + start += rc; + } + + crc = xmm6260_crc_calculate(io_data->radio_data, offset, length); + + rc = write(io_data->boot_fd, &crc, sizeof(crc)); + if (rc != sizeof(crc)) { + ipc_client_log(client, "%s: Failed to write EBL CRC (0x%x)", __func__, crc); + goto fail; + } + + rc = piranha_ack_read(client, io_data->boot_fd, PIRANHA_ACK_EBL); + if (rc < 0) { + ipc_client_log(client, "%s: Failed to read EBL ACK", __func__); + goto fail; + } + + return 0; + +fail: + return -1; +} + +int piranha_psi_send(struct ipc_client *client, struct modemctl_io_data *io_data) +{ + struct piranha_radio_part *radio_part; + int length, offset; + int chunk = 0xdfc; + + int start, end; + unsigned char crc; + uint32_t crc32; + + int v; + int rc; + + radio_part = piranha_radio_part_get(PSI); + if (radio_part == NULL) + goto fail; + + length = radio_part->length; + offset = radio_part->offset; + start = offset; + end = start + length; + + struct piranha_psi_header header = { + .padding = 0xff, + .length[0] = (length >> 8) & 0xff, + .length[1] = length & 0xff, + .magic = PIRANHA_MAGIC_PSI, + }; + + rc = write(io_data->boot_fd, &header, sizeof(header)); + if (rc != sizeof(header)) { + ipc_client_log(client, "%s: Failed to write PSI header", __func__); + goto fail; + } + + while (start < end) { + rc = write(io_data->boot_fd, io_data->radio_data + start, chunk < end - start ? chunk : end - start); + if (rc < 0) { + ipc_client_log(client, "%s: Failed to write PSI data", __func__); + goto fail; + } + + start += rc; + } + + crc = xmm6260_crc_calculate(io_data->radio_data, offset, length); + crc32 = (crc << 24) | 0xffffff; + + rc = write(io_data->boot_fd, &crc32, sizeof(crc32)); + if (rc != sizeof(crc32)) { + ipc_client_log(client, "%s: Failed to write PSI CRC (0x%x)", __func__, crc); + goto fail; + } + + rc = piranha_ack_read(client, io_data->boot_fd, PIRANHA_ACK_PSI); + if (rc < 0) { + ipc_client_log(client, "%s: Failed to read PSI ACK", __func__); + goto fail; + } + + return 0; + +fail: + return -1; +} + +int piranha_modem_bootstrap(struct ipc_client *client) +{ + struct modemctl_io_data io_data; + unsigned short boot_magic[4]; + int length; + int c; + int rc; + + memset(&io_data, 0, sizeof(client, io_data)); + + ipc_client_log(client, "%s: Opening radio image (%s)", __func__, PIRANHA_RADIO_IMAGE); + + io_data.radio_fd = open(PIRANHA_RADIO_IMAGE, O_RDONLY); + if (io_data.radio_fd < 0) { + ipc_client_log(client, "%s: Failed to open radio image (%s): %s", __func__, PIRANHA_RADIO_IMAGE, strerror(errno)); + goto fail; + } + + rc = fstat(io_data.radio_fd, &io_data.radio_stat); + if (rc < 0) + goto fail; + + io_data.radio_data = mmap(0, RADIO_MAP_SIZE, PROT_READ, MAP_SHARED, + io_data.radio_fd, 0); + if (io_data.radio_data == MAP_FAILED) { + ipc_client_log(client, "%s: Failed to mmap radio image: %s", __func__, strerror(errno)); + goto fail; + } + + ipc_client_log(client, "%s: Opening boot device (%s)", __func__, PIRANHA_DEV_BOOT0); + + io_data.boot_fd = open(PIRANHA_DEV_BOOT0, O_RDWR | O_NOCTTY | O_NONBLOCK); + if (io_data.boot_fd < 0) { + ipc_client_log(client, "%s: Failed to open boot device (%s): %s", __func__, PIRANHA_DEV_BOOT0, strerror(errno)); + goto fail; + } + + ipc_client_log(client, "%s: Setting power off", __func__); + + rc = modemctl_modem_power(client, &io_data, false); + if (rc < 0) + goto fail; + + ipc_client_log(client, "%s: Setting power on", __func__); + + rc = modemctl_modem_power(client, &io_data, true); + if (rc < 0) + goto fail; + + ipc_client_log(client, "%s: Writing ATAT on boot device", __func__); + + // Boot 0 + for (c=0 ; c < 10 ; c++) { + if (write(io_data.boot_fd, "ATAT", 4) != 4) { + rc = -1; + continue; + } + + rc = piranha_ack_read(client, io_data.boot_fd, PIRANHA_ACK_BOOT0); + if (rc < 0) + continue; + else + break; + } + + if (rc < 0) { + ipc_client_log(client, "%s: Failed to get boot ACK", __func__); + goto fail; + } + + // PSI + ipc_client_log(client, "%s: Sending PSI", __func__); + + rc = piranha_psi_send(client, &io_data); + if (rc < 0) { + ipc_client_log(client, "%s: Failed to send PSI", __func__); + goto fail; + } + + close(io_data.boot_fd); + + // Boot 1 + ipc_client_log(client, "%s: Opening boot device (%s)", __func__, PIRANHA_DEV_BOOT1); + + io_data.boot_fd = open(PIRANHA_DEV_BOOT1, O_RDWR | O_NOCTTY | O_NONBLOCK); + if (io_data.boot_fd < 0) { + ipc_client_log(client, "%s: Failed to open boot device (%s): %s", __func__, PIRANHA_DEV_BOOT1, strerror(errno)); + goto fail; + } + + boot_magic[0] = boot_magic[1] = 0; + boot_magic[2] = boot_magic[3] = PIRANHA_MAGIC_BOOT1; + length = sizeof(boot_magic); + + rc = write(io_data.boot_fd, &length, sizeof(length)); + if (rc != sizeof(length)) { + ipc_client_log(client, "%s: Failed to write boot magic length", __func__); + goto fail; + } + + rc = write(io_data.boot_fd, &boot_magic, sizeof(boot_magic)); + if (rc != sizeof(boot_magic)) { + ipc_client_log(client, "%s: Failed to write boot magic", __func__); + goto fail; + } + + rc = piranha_ack_read(client, io_data.boot_fd, PIRANHA_ACK_BOOT1); + if (rc < 0) { + ipc_client_log(client, "%s: Failed to read boot ACK", __func__); + goto fail; + } + + // EBL + ipc_client_log(client, "%s: Sending EBL", __func__); + + rc = piranha_ebl_send(client, &io_data); + if (rc < 0) { + ipc_client_log(client, "%s: Failed to send EBL", __func__); + goto fail; + } + + rc = piranha_ebl_set(client, &io_data); + if (rc < 0) { + ipc_client_log(client, "%s: Failed to set PSI", __func__); + goto fail; + } + + // SEC images + ipc_client_log(client, "%s: Sending SEC images", __func__); + + rc = piranha_sec_send(client, &io_data); + if (rc < 0) { + ipc_client_log(client, "%s: Failed to send SEC images", __func__); + goto fail; + } + + rc = 0; + goto done; + +fail: + rc = -1; + +done: + if (io_data.radio_data != MAP_FAILED) { + munmap(io_data.radio_data, RADIO_MAP_SIZE); + } + + if (io_data.link_fd >= 0) { + close(io_data.link_fd); + } + + if (io_data.radio_fd >= 0) { + close(io_data.radio_fd); + } + + if (io_data.boot_fd >= 0) { + close(io_data.boot_fd); + } + + return rc; +} + +// vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/device/piranha/piranha_loader.h b/samsung-ipc/device/piranha/piranha_loader.h new file mode 100644 index 0000000..bf874f8 --- /dev/null +++ b/samsung-ipc/device/piranha/piranha_loader.h @@ -0,0 +1,90 @@ +/* + * Firmware loader for Samsung I9100 (galaxys2) + * Copyright (C) 2012 Alexander Tarasikov + * Copyright (C) 2012 Paul Kocialkowski + * + * based on the incomplete C++ implementation which is + * Copyright (C) 2012 Sergey Gridasov + * + * 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, see . + */ + +#include +#include +#include + +#ifndef __PIRANHA_LOADER_H__ +#define __PIRANHA_LOADER_H__ + +#define PIRANHA_RADIO_IMAGE "/dev/block/mmcblk0p8" +#define PIRANHA_DEV_BOOT0 "/dev/umts_boot0" +#define PIRANHA_DEV_BOOT1 "/dev/umts_boot1" + +#define PIRANHA_MAGIC_PSI 0x30 +#define PIRANHA_MAGIC_BOOT1 0x02 +#define PIRANHA_MAGIC_BOOT_CMD_HEADER 0x02 +#define PIRANHA_MAGIC_BOOT_CMD_TAIL 0x03 +#define PIRANHA_MAGIC_BOOT_CMD_UNKNOWN 0xeaea +#define PIRANHA_MAGIC_BOOT_CMD_SEC_END 0x0000 +#define PIRANHA_MAGIC_BOOT_CMD_HW_RESET 0x00111001 + +#define PIRANHA_ACK_BOOT0 0xffff +#define PIRANHA_ACK_PSI 0xdd01 +#define PIRANHA_ACK_BOOT1 0xaa00 +#define PIRANHA_ACK_EBL_LENGTH 0xcccc +#define PIRANHA_ACK_EBL 0xa551 + +#define PIRANHA_ADDRESS_FIRMWARE 0x60300000 +#define PIRANHA_ADDRESS_NV_DATA 0x60e80000 + +#define PIRANHA_FLAG_NONE (0) +#define PIRANHA_FLAG_SHORT_TAIL (1 << 0) +#define PIRANHA_FLAG_NO_ACK (1 << 1) + +struct piranha_radio_part { + int id; + size_t offset; + size_t length; +}; + +struct piranha_boot_cmd { + int cmd; + uint16_t code; + int flags; +}; + +struct piranha_psi_header { + uint8_t padding; + uint8_t length[2]; + uint8_t magic; +} __attribute__((packed)); + +struct piranha_boot_cmd_header { + uint32_t size; + uint16_t magic; + uint16_t code; + uint16_t data_size; +} __attribute__((packed)); + +struct piranha_boot_cmd_tail { + uint16_t checksum; + uint16_t magic; + uint16_t unknown; +} __attribute__((packed)); + +int piranha_modem_bootstrap(struct ipc_client *client); + +#endif + +// vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/ipc_devices.c b/samsung-ipc/ipc_devices.c index dcf3689..9858136 100644 --- a/samsung-ipc/ipc_devices.c +++ b/samsung-ipc/ipc_devices.c @@ -94,6 +94,26 @@ struct ipc_device_desc ipc_devices[] = { .handlers = &maguro_default_handlers, .gprs_specs = &maguro_gprs_specs, .nv_data_specs = &maguro_nv_data_specs, + }, + { + .name = "piranha", + .board_name = "espresso10", + .kernel_version = NULL, + .fmt_ops = &piranha_fmt_ops, + .rfs_ops = &piranha_rfs_ops, + .handlers = &piranha_default_handlers, + .gprs_specs = &piranha_gprs_specs, + .nv_data_specs = NULL, + }, + { + .name = "piranha", + .board_name = "espresso", + .kernel_version = NULL, + .fmt_ops = &piranha_fmt_ops, + .rfs_ops = &piranha_rfs_ops, + .handlers = &piranha_default_handlers, + .gprs_specs = &piranha_gprs_specs, + .nv_data_specs = NULL, } }; diff --git a/samsung-ipc/ipc_devices.h b/samsung-ipc/ipc_devices.h index ce92476..7822359 100644 --- a/samsung-ipc/ipc_devices.h +++ b/samsung-ipc/ipc_devices.h @@ -70,6 +70,13 @@ extern struct ipc_handlers maguro_default_handlers; extern struct ipc_gprs_specs maguro_gprs_specs; extern struct ipc_nv_data_specs maguro_nv_data_specs; +/* piranha */ +extern struct ipc_ops piranha_fmt_ops; +extern struct ipc_ops piranha_rfs_ops; +extern struct ipc_handlers piranha_default_handlers; +extern struct ipc_gprs_specs piranha_gprs_specs; +extern struct ipc_nv_data_specs piranha_nv_data_specs; + #endif // vim:ts=4:sw=4:expandtab -- cgit v1.1