From 10eb92cac26b29c204f3a66fde2f355a692efce8 Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Wed, 3 Jul 2013 16:10:04 +0200 Subject: Major rework of xmm6260 common code (MIPI and HSIC) and xmm6260 devices code Change-Id: I49fba6329824e1f1ab0aceef91a57f75727a41ab Signed-off-by: Paul Kocialkowski --- Android.mk | 12 +- samsung-ipc/Makefile.am | 37 +- samsung-ipc/device/galaxys2/galaxys2_ipc.c | 402 +++++++++- samsung-ipc/device/galaxys2/galaxys2_ipc.h | 44 ++ samsung-ipc/device/galaxys2/galaxys2_loader.c | 765 ------------------- samsung-ipc/device/galaxys2/galaxys2_loader.h | 82 -- samsung-ipc/device/maguro/maguro_ipc.c | 387 +++++++++- samsung-ipc/device/maguro/maguro_ipc.h | 52 ++ samsung-ipc/device/maguro/maguro_loader.c | 844 --------------------- samsung-ipc/device/maguro/maguro_loader.h | 104 --- samsung-ipc/device/piranha/piranha_ipc.c | 337 +++++++- samsung-ipc/device/piranha/piranha_ipc.h | 44 ++ samsung-ipc/device/piranha/piranha_loader.c | 764 ------------------- samsung-ipc/device/piranha/piranha_loader.h | 90 --- samsung-ipc/device/xmm6260/modem.h | 74 ++ .../device/xmm6260/modem_link_device_hsic.h | 63 ++ samsung-ipc/device/xmm6260/modem_prj.h | 145 +++- samsung-ipc/device/xmm6260/xmm6260.c | 44 ++ samsung-ipc/device/xmm6260/xmm6260.h | 46 ++ samsung-ipc/device/xmm6260/xmm6260_hsic.c | 610 +++++++++++++++ samsung-ipc/device/xmm6260/xmm6260_hsic.h | 70 ++ samsung-ipc/device/xmm6260/xmm6260_ipc.c | 399 ---------- samsung-ipc/device/xmm6260/xmm6260_ipc.h | 63 -- samsung-ipc/device/xmm6260/xmm6260_loader.c | 104 --- samsung-ipc/device/xmm6260/xmm6260_loader.h | 104 --- samsung-ipc/device/xmm6260/xmm6260_mipi.c | 675 ++++++++++++++++ samsung-ipc/device/xmm6260/xmm6260_mipi.h | 74 ++ samsung-ipc/device/xmm6260/xmm6260_modemctl.c | 181 ----- samsung-ipc/device/xmm6260/xmm6260_modemctl.h | 123 --- samsung-ipc/device/xmm6260/xmm6260_sec_modem.c | 500 ++++++++++++ samsung-ipc/device/xmm6260/xmm6260_sec_modem.h | 60 ++ 31 files changed, 3553 insertions(+), 3746 deletions(-) create mode 100644 samsung-ipc/device/galaxys2/galaxys2_ipc.h delete mode 100644 samsung-ipc/device/galaxys2/galaxys2_loader.c delete mode 100644 samsung-ipc/device/galaxys2/galaxys2_loader.h create mode 100644 samsung-ipc/device/maguro/maguro_ipc.h delete mode 100644 samsung-ipc/device/maguro/maguro_loader.c delete mode 100644 samsung-ipc/device/maguro/maguro_loader.h create mode 100644 samsung-ipc/device/piranha/piranha_ipc.h delete mode 100644 samsung-ipc/device/piranha/piranha_loader.c delete mode 100644 samsung-ipc/device/piranha/piranha_loader.h create mode 100644 samsung-ipc/device/xmm6260/modem.h create mode 100755 samsung-ipc/device/xmm6260/modem_link_device_hsic.h create mode 100644 samsung-ipc/device/xmm6260/xmm6260.c create mode 100644 samsung-ipc/device/xmm6260/xmm6260.h create mode 100644 samsung-ipc/device/xmm6260/xmm6260_hsic.c create mode 100644 samsung-ipc/device/xmm6260/xmm6260_hsic.h delete mode 100644 samsung-ipc/device/xmm6260/xmm6260_ipc.c delete mode 100644 samsung-ipc/device/xmm6260/xmm6260_ipc.h delete mode 100644 samsung-ipc/device/xmm6260/xmm6260_loader.c delete mode 100644 samsung-ipc/device/xmm6260/xmm6260_loader.h create mode 100644 samsung-ipc/device/xmm6260/xmm6260_mipi.c create mode 100644 samsung-ipc/device/xmm6260/xmm6260_mipi.h delete mode 100644 samsung-ipc/device/xmm6260/xmm6260_modemctl.c delete mode 100644 samsung-ipc/device/xmm6260/xmm6260_modemctl.h create mode 100644 samsung-ipc/device/xmm6260/xmm6260_sec_modem.c create mode 100644 samsung-ipc/device/xmm6260/xmm6260_sec_modem.h diff --git a/Android.mk b/Android.mk index 1e47081..9b5cf17 100644 --- a/Android.mk +++ b/Android.mk @@ -60,17 +60,15 @@ samsung-ipc_files := \ samsung-ipc/sec.c \ samsung-ipc/sms.c \ samsung-ipc/util.c \ + samsung-ipc/device/xmm6160/xmm6160.c \ + samsung-ipc/device/xmm6260/xmm6260.c \ + samsung-ipc/device/xmm6260/xmm6260_hsic.c \ + samsung-ipc/device/xmm6260/xmm6260_mipi.c \ + samsung-ipc/device/xmm6260/xmm6260_sec_modem.c \ samsung-ipc/device/crespo/crespo_ipc.c \ samsung-ipc/device/aries/aries_ipc.c \ - samsung-ipc/device/xmm6160/xmm6160.c \ - samsung-ipc/device/xmm6260/xmm6260_loader.c \ - samsung-ipc/device/xmm6260/xmm6260_modemctl.c \ - samsung-ipc/device/xmm6260/xmm6260_ipc.c \ - 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/piranha/piranha_loader.c \ samsung-ipc/device/piranha/piranha_ipc.c LOCAL_SRC_FILES := $(samsung-ipc_files) diff --git a/samsung-ipc/Makefile.am b/samsung-ipc/Makefile.am index 154bb70..8145ba2 100644 --- a/samsung-ipc/Makefile.am +++ b/samsung-ipc/Makefile.am @@ -32,32 +32,33 @@ libsamsung_ipc_la_SOURCES = \ ipc.h \ ipc_devices.h \ util.h \ + device/xmm6160/xmm6160.c \ + device/xmm6160/xmm6160.h \ + device/xmm6260/xmm6260.c \ + device/xmm6260/xmm6260_hsic.c \ + device/xmm6260/xmm6260_mipi.c \ + device/xmm6260/xmm6260_sec_modem.c \ + device/xmm6260/xmm6260.h \ + device/xmm6260/xmm6260_hsic.h \ + device/xmm6260/xmm6260_mipi.h \ + device/xmm6260/xmm6260_sec_modem.h \ + device/xmm6260/modem.h \ + device/xmm6260/modem_link_device_hsic.h \ + device/xmm6260/modem_prj.h \ device/crespo/crespo_ipc.c \ + device/crespo/crespo_ipc.h \ + device/crespo/crespo_modem_ctl.h \ device/aries/aries_ipc.c \ - device/aries/sipc4.h \ device/aries/aries_ipc.h \ + device/aries/sipc4.h \ device/aries/onedram.h \ device/aries/phonet.h \ - device/crespo/crespo_modem_ctl.h \ - device/crespo/crespo_ipc.h \ - device/xmm6160/xmm6160.c \ - device/xmm6160/xmm6160.h \ - device/xmm6260/xmm6260_loader.c \ - device/xmm6260/xmm6260_loader.h \ - device/xmm6260/xmm6260_modemctl.c \ - device/xmm6260/xmm6260_modemctl.h \ - device/xmm6260/xmm6260_ipc.c \ - device/xmm6260/xmm6260_ipc.h \ - device/xmm6260/modem_prj.h \ - device/galaxys2/galaxys2_loader.c \ - device/galaxys2/galaxys2_loader.h \ device/galaxys2/galaxys2_ipc.c \ - device/maguro/maguro_loader.c \ - device/maguro/maguro_loader.h \ + device/galaxys2/galaxys2_ipc.h \ device/maguro/maguro_ipc.c \ - device/piranha/piranha_loader.c \ - device/piranha/piranha_loader.h \ + device/maguro/maguro_ipc.h \ device/piranha/piranha_ipc.c \ + device/piranha/piranha_ipc.h \ $(NULL) libsamsung_ipc_la_LIBADD = \ diff --git a/samsung-ipc/device/galaxys2/galaxys2_ipc.c b/samsung-ipc/device/galaxys2/galaxys2_ipc.c index d68cf0d..5c1c9c3 100644 --- a/samsung-ipc/device/galaxys2/galaxys2_ipc.c +++ b/samsung-ipc/device/galaxys2/galaxys2_ipc.c @@ -1,13 +1,7 @@ -/** +/* * This file is part of libsamsung-ipc. * - * Copyright (C) 2012 Alexander Tarasikov - * Copyright (C) 2011 Paul Kocialkowski - * based on crespo IPC code which is: - * - * Copyright (C) 2011 Paul Kocialkowski - * Joerie de Gram - * Simon Busch + * 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 @@ -24,44 +18,400 @@ */ #include +#include +#include +#include +#include + +#include +#include + +#include "xmm6260.h" +#include "xmm6260_hsic.h" +#include "xmm6260_sec_modem.h" +#include "galaxys2_ipc.h" + +int galaxys2_ipc_bootstrap(struct ipc_client *client) +{ + void *modem_image_data = NULL; + int modem_image_fd = -1; + int modem_boot_fd = -1; + int modem_link_fd = -1; + + unsigned char *p; + int rc; + + if (client == NULL) + return -1; + + ipc_client_log(client, "Starting galaxys2 modem bootstrap"); + + modem_image_fd = open(GALAXYS2_MODEM_IMAGE_DEVICE, O_RDONLY); + if (modem_image_fd < 0) { + ipc_client_log(client, "Opening modem image device failed"); + goto error; + } + ipc_client_log(client, "Opened modem image device"); + + modem_image_data = mmap(0, GALAXYS2_MODEM_IMAGE_SIZE, PROT_READ, MAP_SHARED, modem_image_fd, 0); + if (modem_image_data == NULL || modem_image_data == (void *) 0xffffffff) { + ipc_client_log(client, "Mapping modem image data to memory failed"); + goto error; + } + ipc_client_log(client, "Mapped modem image data to memory"); + + modem_boot_fd = open(XMM6260_SEC_MODEM_BOOT0_DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK); + if (modem_boot_fd < 0) { + ipc_client_log(client, "Opening modem boot device failed"); + goto error; + } + ipc_client_log(client, "Opened modem boot device"); + + modem_link_fd = open(XMM6260_SEC_MODEM_LINK_PM_DEVICE, O_RDWR); + if (modem_link_fd < 0) { + ipc_client_log(client, "Opening modem link device failed"); + goto error; + } + ipc_client_log(client, "Opened modem link device"); + + rc = xmm6260_sec_modem_power(modem_boot_fd, 0); + rc |= xmm6260_sec_modem_link_control_enable(modem_link_fd, 0); + rc |= xmm6260_sec_modem_hci_power(0); + rc |= xmm6260_sec_modem_link_control_active(modem_link_fd, 0); + + if (rc < 0) { + ipc_client_log(client, "Turning the modem off failed"); + goto error; + } + ipc_client_log(client, "Turned the modem off"); + + rc = xmm6260_sec_modem_power(modem_boot_fd, 1); + rc |= xmm6260_sec_modem_link_control_enable(modem_link_fd, 1); + rc |= xmm6260_sec_modem_hci_power(1); + rc |= xmm6260_sec_modem_link_control_active(modem_link_fd, 1); + + if (rc < 0) { + ipc_client_log(client, "Turning the modem on failed"); + goto error; + } + ipc_client_log(client, "Turned the modem on"); + + rc = xmm6260_sec_modem_link_connected_wait(modem_link_fd); + if (rc < 0) { + ipc_client_log(client, "Waiting for link connected failed"); + goto error; + } + ipc_client_log(client, "Waited for link connected"); + + p = (unsigned char *) modem_image_data + GALAXYS2_PSI_OFFSET; + + rc = xmm6260_hsic_psi_send(client, modem_boot_fd, (void *) p, GALAXYS2_PSI_SIZE); + if (rc < 0) { + ipc_client_log(client, "Sending XMM6260 HSIC PSI failed"); + goto error; + } + ipc_client_log(client, "Sent XMM6260 HSIC PSI"); + + p = (unsigned char *) modem_image_data + GALAXYS2_EBL_OFFSET; + + rc = xmm6260_hsic_ebl_send(client, modem_boot_fd, (void *) p, GALAXYS2_EBL_SIZE); + if (rc < 0) { + ipc_client_log(client, "Sending XMM6260 HSIC EBL failed"); + goto error; + } + ipc_client_log(client, "Sent XMM6260 HSIC EBL"); + + rc = xmm6260_hsic_port_config_send(client, modem_boot_fd); + if (rc < 0) { + ipc_client_log(client, "Sending XMM6260 HSIC port config failed"); + goto error; + } + ipc_client_log(client, "Sent XMM6260 HSIC port config"); + + p = (unsigned char *) modem_image_data + GALAXYS2_SEC_START_OFFSET; + + rc = xmm6260_hsic_sec_start_send(client, modem_boot_fd, (void *) p, GALAXYS2_SEC_START_SIZE); + if (rc < 0) { + ipc_client_log(client, "Sending XMM6260 HSIC SEC start failed"); + goto error; + } + ipc_client_log(client, "Sent XMM6260 HSIC SEC start"); + + p = (unsigned char *) modem_image_data + GALAXYS2_FIRMWARE_OFFSET; + + rc = xmm6260_hsic_firmware_send(client, modem_boot_fd, (void *) p, GALAXYS2_FIRMWARE_SIZE); + if (rc < 0) { + ipc_client_log(client, "Sending XMM6260 HSIC firmware failed"); + goto error; + } + ipc_client_log(client, "Sent XMM6260 HSIC firmware"); + + rc = xmm6260_hsic_nv_data_send(client, modem_boot_fd); + if (rc < 0) { + ipc_client_log(client, "Sending XMM6260 HSIC nv_data failed"); + goto error; + } + ipc_client_log(client, "Sent XMM6260 HSIC nv_data"); + + rc = xmm6260_hsic_sec_end_send(client, modem_boot_fd); + if (rc < 0) { + ipc_client_log(client, "Sending XMM6260 HSIC SEC end failed"); + goto error; + } + ipc_client_log(client, "Sent XMM6260 HSIC SEC end"); + + rc = xmm6260_hsic_hw_reset_send(client, modem_boot_fd); + if (rc < 0) { + ipc_client_log(client, "Sending XMM6260 HSIC HW reset failed"); + goto error; + } + ipc_client_log(client, "Sent XMM6260 HSIC HW reset"); + + usleep(300000); + + rc = xmm6260_sec_modem_link_get_hostwake_wait(modem_link_fd); + if (rc < 0) { + ipc_client_log(client, "Waiting for host wake failed"); + } + + rc = xmm6260_sec_modem_link_control_enable(modem_link_fd, 0); + rc |= xmm6260_sec_modem_hci_power(0); + rc |= xmm6260_sec_modem_link_control_active(modem_link_fd, 0); + + if (rc < 0) { + ipc_client_log(client, "Turning the modem off failed"); + goto error; + } + + rc = xmm6260_sec_modem_link_get_hostwake_wait(modem_link_fd); + if (rc < 0) { + ipc_client_log(client, "Waiting for host wake failed"); + goto error; + } + ipc_client_log(client, "Waited for host wake"); + + rc = xmm6260_sec_modem_link_control_enable(modem_link_fd, 1); + rc |= xmm6260_sec_modem_hci_power(1); + rc |= xmm6260_sec_modem_link_control_active(modem_link_fd, 1); + + if (rc < 0) { + ipc_client_log(client, "Turning the modem on failed"); + goto error; + } + + rc = xmm6260_sec_modem_link_connected_wait(modem_link_fd); + if (rc < 0) { + ipc_client_log(client, "Waiting for link connected failed"); + goto error; + } + ipc_client_log(client, "Waited for link connected"); + + usleep(300000); + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + if (modem_image_data != NULL) + munmap(modem_image_data, GALAXYS2_MODEM_IMAGE_SIZE); + + if (modem_image_fd >= 0) + close(modem_image_fd); + + if (modem_boot_fd >= 0) + close(modem_boot_fd); + + if (modem_link_fd >= 0) + close(modem_link_fd); + + return rc; +} + + +int galaxys2_ipc_fmt_send(struct ipc_client *client, struct ipc_message_info *request) +{ + return xmm6260_sec_modem_ipc_fmt_send(client, request); +} + +int galaxys2_ipc_fmt_recv(struct ipc_client *client, struct ipc_message_info *response) +{ + return xmm6260_sec_modem_ipc_fmt_recv(client, response); +} + +int galaxys2_ipc_rfs_send(struct ipc_client *client, struct ipc_message_info *request) +{ + return xmm6260_sec_modem_ipc_rfs_send(client, request); +} + +int galaxys2_ipc_rfs_recv(struct ipc_client *client, struct ipc_message_info *response) +{ + return xmm6260_sec_modem_ipc_rfs_recv(client, response); +} + +int galaxys2_ipc_open(void *data, int type) +{ + struct galaxys2_ipc_transport_data *transport_data; + + if (data == NULL) + return -1; + + transport_data = (struct galaxys2_ipc_transport_data *) data; + + transport_data->fd = xmm6260_sec_modem_ipc_open(type); + if (transport_data->fd < 0) + return -1; + + return 0; +} + +int galaxys2_ipc_close(void *data) +{ + struct galaxys2_ipc_transport_data *transport_data; + + if (data == NULL) + return -1; + + transport_data = (struct galaxys2_ipc_transport_data *) data; + + xmm6260_sec_modem_ipc_close(transport_data->fd); + transport_data->fd = -1; + + return 0; +} + +int galaxys2_ipc_read(void *data, void *buffer, unsigned int length) +{ + struct galaxys2_ipc_transport_data *transport_data; + int rc; + + if (data == NULL) + return -1; + + transport_data = (struct galaxys2_ipc_transport_data *) data; + + rc = xmm6260_sec_modem_ipc_read(transport_data->fd, buffer, length); + return rc; +} + +int galaxys2_ipc_write(void *data, void *buffer, unsigned int length) +{ + struct galaxys2_ipc_transport_data *transport_data; + int rc; + + if (data == NULL) + return -1; + + transport_data = (struct galaxys2_ipc_transport_data *) data; + + rc = xmm6260_sec_modem_ipc_write(transport_data->fd, buffer, length); + return rc; +} + +int galaxys2_ipc_poll(void *data, struct timeval *timeout) +{ + struct galaxys2_ipc_transport_data *transport_data; + int rc; + + if (data == NULL) + return -1; + + transport_data = (struct galaxys2_ipc_transport_data *) data; + + rc = xmm6260_sec_modem_ipc_poll(transport_data->fd, timeout); + return rc; +} + +int galaxys2_ipc_power_on(void *data) +{ + return 0; +} + +int galaxys2_ipc_power_off(void *data) +{ + int fd; + int rc; + + fd = open(XMM6260_SEC_MODEM_BOOT0_DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK); + if (fd < 0) + return -1; + + rc = xmm6260_sec_modem_power(fd, 0); + + close(fd); + + if (rc < 0) + return -1; + + return 0; +} + +int galaxys2_ipc_data_create(void **transport_data, void **power_data, void **gprs_data) +{ + if (transport_data == NULL) + return -1; + + *transport_data = (void *) malloc(sizeof(struct galaxys2_ipc_transport_data)); + memset(*transport_data, 0, sizeof(struct galaxys2_ipc_transport_data)); + + return 0; +} + +int galaxys2_ipc_data_destroy(void *transport_data, void *power_data, void *gprs_data) +{ + if (transport_data == NULL) + return -1; + + free(transport_data); + + return 0; +} + +char *galaxys2_ipc_gprs_get_iface(int cid) +{ + return xmm6260_sec_modem_ipc_gprs_get_iface(cid); +} -#include "ipc.h" -#include "xmm6260_ipc.h" -#include "galaxys2_loader.h" +int galaxys2_ipc_gprs_get_capabilities(struct ipc_client_gprs_capabilities *capabilities) +{ + return xmm6260_sec_modem_ipc_gprs_get_capabilities(capabilities); +} struct ipc_ops galaxys2_ipc_fmt_ops = { .bootstrap = galaxys2_ipc_bootstrap, - .send = xmm6260_ipc_fmt_send, - .recv = xmm6260_ipc_fmt_recv, + .send = galaxys2_ipc_fmt_send, + .recv = galaxys2_ipc_fmt_recv, }; struct ipc_ops galaxys2_ipc_rfs_ops = { .bootstrap = NULL, - .send = xmm6260_ipc_rfs_send, - .recv = xmm6260_ipc_rfs_recv, + .send = galaxys2_ipc_rfs_send, + .recv = galaxys2_ipc_rfs_recv, }; struct ipc_handlers galaxys2_ipc_handlers = { - .open = xmm6260_ipc_open, - .close = xmm6260_ipc_close, - .read = xmm6260_ipc_read, - .write = xmm6260_ipc_write, - .poll = xmm6260_ipc_poll, + .read = galaxys2_ipc_read, + .write = galaxys2_ipc_write, + .open = galaxys2_ipc_open, + .close = galaxys2_ipc_close, + .poll = galaxys2_ipc_poll, .transport_data = NULL, - .power_on = xmm6260_ipc_power_on, - .power_off = xmm6260_ipc_power_off, + .power_on = galaxys2_ipc_power_on, + .power_off = galaxys2_ipc_power_off, .power_data = NULL, .gprs_activate = NULL, .gprs_deactivate = NULL, .gprs_data = NULL, - .data_create = xmm6260_ipc_data_create, - .data_destroy = xmm6260_ipc_data_destroy, + .data_create = galaxys2_ipc_data_create, + .data_destroy = galaxys2_ipc_data_destroy, }; struct ipc_gprs_specs galaxys2_ipc_gprs_specs = { - .gprs_get_iface = xmm6260_ipc_gprs_get_iface, - .gprs_get_capabilities = xmm6260_ipc_gprs_get_capabilities, + .gprs_get_iface = galaxys2_ipc_gprs_get_iface, + .gprs_get_capabilities = galaxys2_ipc_gprs_get_capabilities, }; // vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/device/galaxys2/galaxys2_ipc.h b/samsung-ipc/device/galaxys2/galaxys2_ipc.h new file mode 100644 index 0000000..a7e17c2 --- /dev/null +++ b/samsung-ipc/device/galaxys2/galaxys2_ipc.h @@ -0,0 +1,44 @@ +/* + * 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 . + * + */ + +#ifndef __GALAXYS2_IPC_H__ +#define __GALAXYS2_IPC_H__ + +#define GALAXYS2_MODEM_IMAGE_SIZE 0x1000000 +#define GALAXYS2_PSI_OFFSET 0 +#define GALAXYS2_PSI_SIZE 0xF000 +#define GALAXYS2_EBL_OFFSET 0xF000 +#define GALAXYS2_EBL_SIZE 0x19000 +#define GALAXYS2_SEC_START_OFFSET 0x9FF800 +#define GALAXYS2_SEC_START_SIZE 0x800 +#define GALAXYS2_FIRMWARE_OFFSET 0x28000 +#define GALAXYS2_FIRMWARE_SIZE 0x9D8000 +#define GALAXYS2_NV_DATA_OFFSET 0xA00000 +#define GALAXYS2_NV_DATA_SIZE 0x200000 + +#define GALAXYS2_MODEM_IMAGE_DEVICE "/dev/block/mmcblk0p8" + +struct galaxys2_ipc_transport_data { + int fd; +}; + +#endif + +// vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/device/galaxys2/galaxys2_loader.c b/samsung-ipc/device/galaxys2/galaxys2_loader.c deleted file mode 100644 index 03dca93..0000000 --- a/samsung-ipc/device/galaxys2/galaxys2_loader.c +++ /dev/null @@ -1,765 +0,0 @@ -/* - * 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 -#include - -#include -#include -#include -#include -#include - -//for timeval -#include - -//for mmap -#include -#include - -#include "ipc.h" - -#include "galaxys2_loader.h" -#include "xmm6260_loader.h" -#include "xmm6260_modemctl.h" -#include "modem_prj.h" - -#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) - -/* - * Locations of the firmware components in the Samsung firmware - */ - -struct xmm6260_radio_part galaxys2_radio_parts[] = { - [PSI] = { - .offset = 0, - .length = 0xf000, - }, - [EBL] = { - .offset = 0xf000, - .length = 0x19000, - }, - [SECURE_IMAGE] = { - .offset = 0x9ff800, - .length = 0x800, - }, - [FIRMWARE] = { - .offset = 0x28000, - .length = 0x9d8000, - }, - [NVDATA] = { - .offset = 0xa00000, - .length = 2 << 20, - } -}; - -struct galaxys2_boot_cmd_desc galaxys2_boot_cmd_desc[] = { - [SetPortConf] = { - .code = 0x86, - .data_size = 0x800, - .need_ack = 1, - }, - [ReqSecStart] = { - .code = 0x204, - .data_size = 0x4000, - .need_ack = 1, - }, - [ReqSecEnd] = { - .code = 0x205, - .data_size = 0x4000, - .need_ack = 1, - }, - [ReqForceHwReset] = { - .code = 0x208, - .data_size = 0x4000, - .need_ack = 0, - }, - [ReqFlashSetAddress] = { - .code = 0x802, - .data_size = 0x4000, - .need_ack = 1, - }, - [ReqFlashWriteBlock] = { - .code = 0x804, - .data_size = 0x4000, - .need_ack = 0, - } -}; - -static int galaxys2_send_image(struct ipc_client *client, - struct modemctl_io_data *io_data, enum xmm6260_image type) -{ - int ret = -1; - - if (type >= ARRAY_SIZE(galaxys2_radio_parts)) { - ipc_client_log(client, "Error: bad image type %x", type); - goto fail; - } - size_t length = galaxys2_radio_parts[type].length; - size_t offset = galaxys2_radio_parts[type].offset; - - size_t start = offset; - size_t end = length + start; - - //dump some image bytes - ipc_client_log(client, "image start"); - - while (start < end) { - ret = write(io_data->boot_fd, io_data->radio_data + start, end - start); - if (ret < 0) { - ipc_client_log(client, "failed to write image chunk"); - goto fail; - } - start += ret; - } - - unsigned char crc = xmm6260_crc_calculate(io_data->radio_data, offset, length); - - if ((ret = write(io_data->boot_fd, &crc, 1)) < 1) { - ipc_client_log(client, "failed to write CRC"); - goto fail; - } - else { - ipc_client_log(client, "wrote CRC %x", crc); - } - - return 0; - -fail: - return ret; -} - -static int galaxys2_send_psi(struct ipc_client *client, struct modemctl_io_data *io_data) -{ - size_t length = galaxys2_radio_parts[PSI].length; - - struct galaxys2_psi_header hdr = { - .magic = XMM_PSI_MAGIC, - .length = length, - .padding = 0xff, - }; - int ret = -1; - - if ((ret = write(io_data->boot_fd, &hdr, sizeof(hdr))) != sizeof(hdr)) { - ipc_client_log(client, "%s: failed to write header, ret %d", __func__, ret); - goto fail; - } - - if ((ret = galaxys2_send_image(client, io_data, PSI)) < 0) { - ipc_client_log(client, "Error: failed to send PSI image"); - goto fail; - } - - int i; - for (i = 0; i < 22; i++) { - char ack; - if (expect_read(io_data->boot_fd, &ack, 1) < 1) { - ipc_client_log(client, "failed to read ACK byte %d", i); - goto fail; - } - } - - if ((ret = expect_data(io_data->boot_fd, "\x1", 1)) < 0) { - ipc_client_log(client, "failed to wait for first ACK"); - goto fail; - } - - if ((ret = expect_data(io_data->boot_fd, "\x1", 1)) < 0) { - ipc_client_log(client, "failed to wait for second ACK"); - goto fail; - } - - if ((ret = expect_data(io_data->boot_fd, PSI_ACK_MAGIC, 2)) < 0) { - ipc_client_log(client, "Error: failed to receive PSI ACK"); - goto fail; - } - else { - ipc_client_log(client, "received PSI ACK"); - } - - return 0; - -fail: - return ret; -} - -static int galaxys2_send_ebl(struct ipc_client *client, struct modemctl_io_data *io_data) -{ - int ret; - int fd = io_data->boot_fd; - unsigned length = galaxys2_radio_parts[EBL].length; - - if ((ret = write(fd, &length, sizeof(length))) < 0) { - ipc_client_log(client, "Error: failed to write EBL length"); - goto fail; - } - - if ((ret = expect_data(fd, EBL_HDR_ACK_MAGIC, 2)) < 0) { - ipc_client_log(client, "Error: failed to wait for EBL header ACK"); - goto fail; - } - - if ((ret = galaxys2_send_image(client, io_data, EBL)) < 0) { - ipc_client_log(client, "Error: failed to send EBL image"); - goto fail; - } - - if ((ret = expect_data(fd, EBL_IMG_ACK_MAGIC, 2)) < 0) { - ipc_client_log(client, "Error: failed to wait for EBL image ACK"); - goto fail; - } - - return 0; - -fail: - return ret; -} - -static int galaxys2_boot_cmd(struct ipc_client *client, - struct modemctl_io_data *io_data, enum xmm6260_boot_cmd cmd, - void *data, size_t data_size) -{ - int ret = 0; - char *cmd_data = 0; - if (cmd >= ARRAY_SIZE(galaxys2_boot_cmd_desc)) { - ipc_client_log(client, "Error: bad command %x\n", cmd); - goto done_or_fail; - } - - unsigned cmd_code = galaxys2_boot_cmd_desc[cmd].code; - - uint16_t magic = (data_size & 0xffff) + cmd_code; - unsigned char *ptr = (unsigned char*)data; - size_t i; - for (i = 0; i < data_size; i++) { - magic += ptr[i]; - } - - struct galaxys2_boot_cmd header = { - .check = magic, - .cmd = cmd_code, - .data_size = data_size, - }; - - size_t cmd_size = galaxys2_boot_cmd_desc[cmd].data_size; - size_t buf_size = cmd_size + sizeof(header); - - cmd_data = (char*)malloc(buf_size); - if (!cmd_data) { - ipc_client_log(client, "Error: failed to allocate command buffer"); - ret = -ENOMEM; - goto done_or_fail; - } - memset(cmd_data, 0, buf_size); - memcpy(cmd_data, &header, sizeof(header)); - memcpy(cmd_data + sizeof(header), data, data_size); - - if ((ret = write(io_data->boot_fd, cmd_data, buf_size)) < 0) { - ipc_client_log(client, "Error: failed to write command to socket"); - goto done_or_fail; - } - - if ((unsigned)ret != buf_size) { - ipc_client_log(client, "Error: written %d bytes of %d", ret, buf_size); - ret = -EINVAL; - goto done_or_fail; - } - - if (!galaxys2_boot_cmd_desc[cmd].need_ack) { - ret = 0; - goto done_or_fail; - } - - struct galaxys2_boot_cmd ack = { - .check = 0, - }; - if ((ret = expect_read(io_data->boot_fd, &ack, sizeof(ack))) < 0) { - ipc_client_log(client, "Error: failed to receive ack for cmd %x", header.cmd); - goto done_or_fail; - } - - if (ret != sizeof(ack)) { - ipc_client_log(client, "Error: received %x bytes of %x for ack", ret, sizeof(ack)); - ret = -EINVAL; - goto done_or_fail; - } - - if (ack.cmd != header.cmd) { - ipc_client_log(client, "Error: ack cmd %x does not match request %x", ack.cmd, header.cmd); - ret = -EINVAL; - goto done_or_fail; - } - - if ((ret = expect_read(io_data->boot_fd, cmd_data, cmd_size)) < 0) { - ipc_client_log(client, "Error: failed to receive reply data"); - goto done_or_fail; - } - - if ((unsigned)ret != cmd_size) { - ipc_client_log(client, "Error: received %x bytes of %x for reply data", ret, cmd_size); - ret = -EINVAL; - goto done_or_fail; - } - -done_or_fail: - - if (cmd_data) { - free(cmd_data); - } - - return ret; -} - -static int galaxys2_boot_info_ack(struct ipc_client *client, - struct modemctl_io_data *io_data) -{ - int ret; - struct galaxys2_boot_info info; - - if ((ret = expect_read(io_data->boot_fd, &info, sizeof(info))) != sizeof(info)) { - ipc_client_log(client, "Error: failed to receive Boot Info ret=%d", ret); - ret = -1; - goto fail; - } - else { - ipc_client_log(client, "received Boot Info"); - } - - if ((ret = galaxys2_boot_cmd(client, io_data, SetPortConf, &info, sizeof(info))) < 0) { - ipc_client_log(client, "Error: failed to send SetPortConf command"); - goto fail; - } - else { - ipc_client_log(client, "sent SetPortConf command"); - } - - return 0; - -fail: - return ret; -} - -static int galaxys2_send_image_data(struct ipc_client *client, - struct modemctl_io_data *io_data, uint32_t addr, - void *data, int data_len) -{ - int ret = 0; - int count = 0; - char *data_p = (char *) data; - - if ((ret = galaxys2_boot_cmd(client, io_data, ReqFlashSetAddress, &addr, 4)) < 0) { - ipc_client_log(client, "Error: failed to send ReqFlashSetAddress"); - goto fail; - } - else { - ipc_client_log(client, "sent ReqFlashSetAddress"); - } - - while (count < data_len) { - int rest = data_len - count; - int chunk = rest < SEC_DOWNLOAD_CHUNK ? rest : SEC_DOWNLOAD_CHUNK; - - ret = galaxys2_boot_cmd(client, io_data, ReqFlashWriteBlock, data_p, chunk); - if (ret < 0) { - ipc_client_log(client, "Error: failed to send data chunk"); - goto fail; - } - - data_p += chunk; - count += chunk; - } - - usleep(SEC_DOWNLOAD_DELAY_US); - -fail: - return ret; -} - -static int galaxys2_send_image_addr(struct ipc_client *client, - struct modemctl_io_data *io_data, uint32_t addr, enum xmm6260_image type) -{ - uint32_t offset = galaxys2_radio_parts[type].offset; - uint32_t length = galaxys2_radio_parts[type].length; - char *start = io_data->radio_data + offset; - int ret = 0; - - ret = galaxys2_send_image_data(client, io_data, addr, start, length); - - return ret; -} - -static int galaxys2_send_secure_images(struct ipc_client *client, - struct modemctl_io_data *io_data) -{ - int ret = 0; - - uint32_t sec_off = galaxys2_radio_parts[SECURE_IMAGE].offset; - uint32_t sec_len = galaxys2_radio_parts[SECURE_IMAGE].length; - void *sec_img = io_data->radio_data + sec_off; - void *nv_data = NULL; - - if ((ret = galaxys2_boot_cmd(client, io_data, ReqSecStart, sec_img, sec_len)) < 0) { - ipc_client_log(client, "Error: failed to write ReqSecStart"); - goto fail; - } - else { - ipc_client_log(client, "sent ReqSecStart"); - } - - if ((ret = galaxys2_send_image_addr(client, io_data, FW_LOAD_ADDR, FIRMWARE)) < 0) { - ipc_client_log(client, "Error: failed to send FIRMWARE image"); - goto fail; - } - else { - ipc_client_log(client, "sent FIRMWARE image"); - } - - if (nv_data_check(client) < 0) - goto fail; - - if (nv_data_md5_check(client) < 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, "Error: failed to read NVDATA image"); - goto fail; - } - - if ((ret = galaxys2_send_image_data(client, io_data, NVDATA_LOAD_ADDR, nv_data, 2 << 20)) < 0) { - ipc_client_log(client, "Error: failed to send NVDATA image"); - goto fail; - } - else { - ipc_client_log(client, "sent NVDATA image"); - } - - free(nv_data); - - if ((ret = galaxys2_boot_cmd(client, io_data, ReqSecEnd, - BL_END_MAGIC, BL_END_MAGIC_LEN)) < 0) - { - ipc_client_log(client, "Error: failed to write ReqSecEnd"); - goto fail; - } - else { - ipc_client_log(client, "sent ReqSecEnd"); - } - - ret = galaxys2_boot_cmd(client, io_data, ReqForceHwReset, - BL_RESET_MAGIC, BL_RESET_MAGIC_LEN); - if (ret < 0) { - ipc_client_log(client, "Error: failed to write ReqForceHwReset"); - goto fail; - } - else { - ipc_client_log(client, "sent ReqForceHwReset"); - } - -fail: - return ret; -} - -/* - * i9200 (Galaxy S2) board-specific code - */ - -/* - * Power management - */ -static int galaxys2_ehci_setpower(struct ipc_client *client, bool enabled) { - int ret = -1; - - ipc_client_log(client, "%s: enabled=%d", __func__, enabled); - - int ehci_fd = open(I9100_EHCI_PATH, O_RDWR); - if (ehci_fd < 0) { - ipc_client_log(client, "Error: failed to open EHCI fd"); - ret = -ENODEV; - goto fail; - } - else { - ipc_client_log(client, "opened EHCI %s: fd=%d", I9100_EHCI_PATH, ehci_fd); - } - - ret = write(ehci_fd, enabled ? "1" : "0", 1); - - //must write exactly one byte - if (ret <= 0) { - ipc_client_log(client, "Error: failed to set EHCI power"); - } - else { - ipc_client_log(client, "set EHCI power"); - } - -fail: - if (ehci_fd >= 0) { - close(ehci_fd); - } - - return ret; -} - -static int galaxys2_modem_reboot(struct ipc_client *client, - struct modemctl_io_data *io_data, bool hard) { - int ret; - - //wait for link to become ready before redetection - if (!hard) { - if ((ret = modemctl_wait_link_ready(client, io_data)) < 0) { - ipc_client_log(client, "Error: failed to wait for link to get ready for redetection"); - goto fail; - } - else { - ipc_client_log(client, "link ready for redetection"); - } - } - - /* - * Disable the hardware to ensure consistent state - */ - if (hard) { - if ((ret = modemctl_modem_power(client, io_data, false)) < 0) { - ipc_client_log(client, "Error: failed to disable xmm6260 power"); - goto fail; - } - else { - ipc_client_log(client, "disabled xmm6260 power"); - } - } - - if ((ret = modemctl_link_set_enabled(client, io_data, false)) < 0) { - ipc_client_log(client, "Error: failed to disable I9100 HSIC link"); - goto fail; - } - else { - ipc_client_log(client, "disabled I9100 HSIC link"); - } - - if ((ret = galaxys2_ehci_setpower(client, false)) < 0) { - ipc_client_log(client, "Error: failed to disable I9100 EHCI"); - goto fail; - } - else { - ipc_client_log(client, "disabled I9100 EHCI"); - } - - if ((ret = modemctl_link_set_active(client, io_data, false)) < 0) { - ipc_client_log(client, "Error: failed to deactivate I9100 HSIC link"); - goto fail; - } - else { - ipc_client_log(client, "deactivated I9100 HSIC link"); - } - - /* - * Now, initialize the hardware - */ - - if ((ret = modemctl_link_set_enabled(client, io_data, true)) < 0) { - ipc_client_log(client, "Error: failed to enable I9100 HSIC link"); - goto fail; - } - else { - ipc_client_log(client, "enabled I9100 HSIC link"); - } - - if ((ret = galaxys2_ehci_setpower(client, true)) < 0) { - ipc_client_log(client, "Error: failed to enable I9100 EHCI"); - goto fail; - } - else { - ipc_client_log(client, "enabled I9100 EHCI"); - } - - if ((ret = modemctl_link_set_active(client, io_data, true)) < 0) { - ipc_client_log(client, "Error: failed to activate I9100 HSIC link"); - goto fail; - } - else { - ipc_client_log(client, "activated I9100 HSIC link"); - } - - if (hard) { - if ((ret = modemctl_modem_power(client, io_data, true)) < 0) { - ipc_client_log(client, "Error: failed to enable xmm6260 power"); - goto fail; - } - else { - ipc_client_log(client, "enabled xmm6260 power"); - } - } - - if ((ret = modemctl_wait_link_ready(client, io_data)) < 0) { - ipc_client_log(client, "Error: failed to wait for link to get ready"); - goto fail; - } - else { - ipc_client_log(client, "link ready"); - } - -fail: - return ret; -} - -int galaxys2_ipc_bootstrap(struct ipc_client *client) { - int ret = 0; - struct modemctl_io_data io_data; - memset(&io_data, 0, sizeof(client, io_data)); - - io_data.radio_fd = open(RADIO_IMAGE, O_RDONLY); - if (io_data.radio_fd < 0) { - ipc_client_log(client, "Error: failed to open radio firmware"); - goto fail; - } - else { - ipc_client_log(client, "opened radio image %s, fd=%d", RADIO_IMAGE, io_data.radio_fd); - } - - if (fstat(io_data.radio_fd, &io_data.radio_stat) < 0) { - ipc_client_log(client, "Error: failed to stat radio image, error %s", strerror(errno)); - 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, "Error: failed to mmap radio image, error %s", strerror(errno)); - goto fail; - } - - io_data.boot_fd = open(BOOT_DEV, O_RDWR | O_NOCTTY | O_NONBLOCK); - if (io_data.boot_fd < 0) { - ipc_client_log(client, "Error: failed to open boot device"); - goto fail; - } - else { - ipc_client_log(client, "opened boot device %s, fd=%d", BOOT_DEV, io_data.boot_fd); - } - - io_data.link_fd = open(LINK_PM, O_RDWR); - if (io_data.link_fd < 0) { - ipc_client_log(client, "Error: failed to open link device"); - goto fail; - } - else { - ipc_client_log(client, "opened link device %s, fd=%d", LINK_PM, io_data.link_fd); - } - - if (galaxys2_modem_reboot(client, &io_data, true)) { - ipc_client_log(client, "Error: failed to hard reset modem"); - goto fail; - } - else { - ipc_client_log(client, "modem hard reset done"); - } - - /* - * Now, actually load the firmware - */ - if (write(io_data.boot_fd, "ATAT", 4) != 4) { - ipc_client_log(client, "Error: failed to write ATAT to boot socket"); - goto fail; - } - else { - ipc_client_log(client, "written ATAT to boot socket, waiting for ACK"); - } - - char buf[2]; - if (expect_read(io_data.boot_fd, buf, 1) < 0) { - ipc_client_log(client, "Error: failed to receive bootloader ACK"); - goto fail; - } - if (expect_read(io_data.boot_fd, buf + 1, 1) < 0) { - ipc_client_log(client, "Error: failed to receive chip IP ACK"); - goto fail; - } - ipc_client_log(client, "receive ID: [%02x %02x]", buf[0], buf[1]); - - if ((ret = galaxys2_send_psi(client, &io_data)) < 0) { - ipc_client_log(client, "Error: failed to upload PSI"); - goto fail; - } - else { - ipc_client_log(client, "PSI download complete"); - } - - if ((ret = galaxys2_send_ebl(client, &io_data)) < 0) { - ipc_client_log(client, "Error: failed to upload EBL"); - goto fail; - } - else { - ipc_client_log(client, "EBL download complete"); - } - - if ((ret = galaxys2_boot_info_ack(client, &io_data)) < 0) { - ipc_client_log(client, "Error: failed to receive Boot Info"); - goto fail; - } - else { - ipc_client_log(client, "Boot Info ACK done"); - } - - if ((ret = galaxys2_send_secure_images(client, &io_data)) < 0) { - ipc_client_log(client, "Error: failed to upload Secure Image"); - goto fail; - } - else { - ipc_client_log(client, "Secure Image download complete"); - } - - usleep(POST_BOOT_TIMEOUT_US); - - if ((ret = galaxys2_modem_reboot(client, &io_data, false))) { - ipc_client_log(client, "Error: failed to soft reset modem"); - goto fail; - } - else { - ipc_client_log(client, "modem soft reset done"); - } - - ipc_client_log(client, "Modem is online!"); - ret = 0; - -fail: - 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 ret; -} - -// vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/device/galaxys2/galaxys2_loader.h b/samsung-ipc/device/galaxys2/galaxys2_loader.h deleted file mode 100644 index e300d70..0000000 --- a/samsung-ipc/device/galaxys2/galaxys2_loader.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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 __GALAXYS2_LOADER_H__ -#define __GALAXYS2_LOADER_H__ - -#define RADIO_IMAGE "/dev/block/mmcblk0p8" -#define I9100_EHCI_PATH "/sys/devices/platform/s5p-ehci/ehci_power" - -#define LINK_POLL_DELAY_US (50 * 1000) -#define LINK_TIMEOUT_MS 2000 - -#define XMM_PSI_MAGIC 0x30 -#define PSI_ACK_MAGIC "\x00\xaa" - -#define EBL_HDR_ACK_MAGIC "\xcc\xcc" -#define EBL_IMG_ACK_MAGIC "\x51\xa5" - -#define BL_END_MAGIC "\x00\x00" -#define BL_END_MAGIC_LEN 2 - -#define BL_RESET_MAGIC "\x01\x10\x11\x00" -#define BL_RESET_MAGIC_LEN 4 - -#define SEC_DOWNLOAD_CHUNK 16384 -#define SEC_DOWNLOAD_DELAY_US (500 * 1000) - -#define POST_BOOT_TIMEOUT_US (600 * 1000) - -#define FW_LOAD_ADDR 0x60300000 -#define NVDATA_LOAD_ADDR 0x60e80000 - -struct galaxys2_boot_cmd_desc { - unsigned code; - size_t data_size; - bool need_ack; -}; - -struct galaxys2_psi_header { - uint8_t magic; - uint16_t length; - uint8_t padding; -} __attribute__((packed)); - -struct galaxys2_boot_info { - uint8_t data[76]; -} __attribute__((packed)); - -struct galaxys2_boot_cmd { - uint16_t check; - uint16_t cmd; - uint32_t data_size; -} __attribute__((packed)); - -int galaxys2_ipc_bootstrap(struct ipc_client *client); - -#endif - -// vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/device/maguro/maguro_ipc.c b/samsung-ipc/device/maguro/maguro_ipc.c index f68e7e6..4774f08 100644 --- a/samsung-ipc/device/maguro/maguro_ipc.c +++ b/samsung-ipc/device/maguro/maguro_ipc.c @@ -1,14 +1,8 @@ -/** +/* * This file is part of libsamsung-ipc. * + * Copyright (C) 2013 Paul Kocialkowski * Copyright (C) 2012 Alexander Tarasikov - * Copyright (C) 2011 Paul Kocialkowski - * - * based on crespo IPC code which is: - * - * Copyright (C) 2011 Paul Kocialkowski - * Joerie de Gram - * Simon Busch * * 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 @@ -25,52 +19,383 @@ */ #include +#include +#include +#include +#include + +#include +#include +#include + +#include "xmm6260.h" +#include "xmm6260_mipi.h" +#include "xmm6260_sec_modem.h" +#include "maguro_ipc.h" + +int maguro_ipc_bootstrap(struct ipc_client *client) +{ + void *modem_image_data = NULL; + int modem_image_fd = -1; + int modem_boot_fd = -1; + void *mps_data = NULL; + + unsigned char *p; + int rc; + + if (client == NULL) + return -1; + + ipc_client_log(client, "Starting maguro modem bootstrap"); + + modem_image_fd = open(MAGURO_MODEM_IMAGE_DEVICE, O_RDONLY); + if (modem_image_fd < 0) { + ipc_client_log(client, "Opening modem image device failed"); + goto error; + } + ipc_client_log(client, "Opened modem image device"); + + modem_image_data = mmap(0, MAGURO_MODEM_IMAGE_SIZE, PROT_READ, MAP_SHARED, modem_image_fd, 0); + if (modem_image_data == NULL || modem_image_data == (void *) 0xffffffff) { + ipc_client_log(client, "Mapping modem image data to memory failed"); + goto error; + } + ipc_client_log(client, "Mapped modem image data to memory"); + + modem_boot_fd = open(XMM6260_SEC_MODEM_BOOT0_DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK); + if (modem_boot_fd < 0) { + ipc_client_log(client, "Opening modem boot device failed"); + goto error; + } + ipc_client_log(client, "Opened modem boot device"); + + rc = xmm6260_sec_modem_power(modem_boot_fd, 0); + if (rc < 0) { + ipc_client_log(client, "Turning the modem off failed"); + goto error; + } + ipc_client_log(client, "Turned the modem off"); + + rc = xmm6260_sec_modem_power(modem_boot_fd, 1); + if (rc < 0) { + ipc_client_log(client, "Turning the modem on failed"); + goto error; + } + ipc_client_log(client, "Turned the modem on"); + + p = (unsigned char *) modem_image_data + MAGURO_PSI_OFFSET; + + rc = xmm6260_mipi_psi_send(client, modem_boot_fd, (void *) p, MAGURO_PSI_SIZE); + if (rc < 0) { + ipc_client_log(client, "Sending XMM6260 MIPI PSI failed"); + goto error; + } + ipc_client_log(client, "Sent XMM6260 MIPI PSI"); + + close(modem_boot_fd); + + modem_boot_fd = open(XMM6260_SEC_MODEM_BOOT1_DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK); + if (modem_boot_fd < 0) { + ipc_client_log(client, "Opening modem boot device failed"); + goto error; + } + ipc_client_log(client, "Opened modem boot device"); + + p = (unsigned char *) modem_image_data + MAGURO_EBL_OFFSET; + + rc = xmm6260_mipi_ebl_send(client, modem_boot_fd, (void *) p, MAGURO_EBL_SIZE); + if (rc < 0) { + ipc_client_log(client, "Sending XMM6260 MIPI EBL failed"); + goto error; + } + ipc_client_log(client, "Sent XMM6260 MIPI EBL"); + + rc = xmm6260_mipi_port_config_send(client, modem_boot_fd); + if (rc < 0) { + ipc_client_log(client, "Sending XMM6260 MIPI port config failed"); + goto error; + } + ipc_client_log(client, "Sent XMM6260 MIPI port config"); + + p = (unsigned char *) modem_image_data + MAGURO_SEC_START_OFFSET; + + rc = xmm6260_mipi_sec_start_send(client, modem_boot_fd, (void *) p, MAGURO_SEC_START_SIZE); + if (rc < 0) { + ipc_client_log(client, "Sending XMM6260 MIPI SEC start failed"); + goto error; + } + ipc_client_log(client, "Sent XMM6260 MIPI SEC start"); + + p = (unsigned char *) modem_image_data + MAGURO_FIRMWARE_OFFSET; + + rc = xmm6260_mipi_firmware_send(client, modem_boot_fd, (void *) p, MAGURO_FIRMWARE_SIZE); + if (rc < 0) { + ipc_client_log(client, "Sending XMM6260 MIPI firmware failed"); + goto error; + } + ipc_client_log(client, "Sent XMM6260 MIPI firmware"); + + rc = xmm6260_mipi_nv_data_send(client, modem_boot_fd); + if (rc < 0) { + ipc_client_log(client, "Sending XMM6260 MIPI nv_data failed"); + goto error; + } + ipc_client_log(client, "Sent XMM6260 MIPI nv_data"); + + mps_data = file_data_read(MAGURO_MPS_DATA_DEVICE, MAGURO_MPS_DATA_SIZE, MAGURO_MPS_DATA_SIZE); + if (mps_data == NULL) { + ipc_client_log(client, "Reading MPS data failed"); + goto error; + } + ipc_client_log(client, "Read MPS data"); + + rc = xmm6260_mipi_mps_data_send(client, modem_boot_fd, mps_data, MAGURO_MPS_DATA_SIZE); + if (rc < 0) { + ipc_client_log(client, "Sending XMM6260 MIPI MPS data failed"); + goto error; + } + ipc_client_log(client, "Sent XMM6260 MIPI MPS data"); + + rc = xmm6260_mipi_sec_end_send(client, modem_boot_fd); + if (rc < 0) { + ipc_client_log(client, "Sending XMM6260 MIPI SEC end failed"); + goto error; + } + ipc_client_log(client, "Sent XMM6260 MIPI SEC end"); + + rc = xmm6260_mipi_hw_reset_send(client, modem_boot_fd); + if (rc < 0) { + ipc_client_log(client, "Sending XMM6260 MIPI HW reset failed"); + goto error; + } + ipc_client_log(client, "Sent XMM6260 MIPI HW reset"); + + rc = xmm6260_sec_modem_status_online_wait(modem_boot_fd); + if (rc < 0) { + ipc_client_log(client, "Waiting for online status failed"); + goto error; + } + ipc_client_log(client, "Waited for online status"); + + rc = xmm6260_sec_modem_boot_power(modem_boot_fd, 0); + if (rc < 0) { + ipc_client_log(client, "Turning modem boot off failed"); + goto error; + } + ipc_client_log(client, "Turned modem boot off"); + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + if (mps_data != NULL) + free(mps_data); + + if (modem_image_data != NULL) + munmap(modem_image_data, MAGURO_MODEM_IMAGE_SIZE); + + if (modem_image_fd >= 0) + close(modem_image_fd); + + if (modem_boot_fd >= 0) + close(modem_boot_fd); + + return rc; +} + + +int maguro_ipc_fmt_send(struct ipc_client *client, struct ipc_message_info *request) +{ + return xmm6260_sec_modem_ipc_fmt_send(client, request); +} + +int maguro_ipc_fmt_recv(struct ipc_client *client, struct ipc_message_info *response) +{ + return xmm6260_sec_modem_ipc_fmt_recv(client, response); +} + +int maguro_ipc_rfs_send(struct ipc_client *client, struct ipc_message_info *request) +{ + return xmm6260_sec_modem_ipc_rfs_send(client, request); +} + +int maguro_ipc_rfs_recv(struct ipc_client *client, struct ipc_message_info *response) +{ + return xmm6260_sec_modem_ipc_rfs_recv(client, response); +} + +int maguro_ipc_open(void *data, int type) +{ + struct maguro_ipc_transport_data *transport_data; + + if (data == NULL) + return -1; + + transport_data = (struct maguro_ipc_transport_data *) data; + + transport_data->fd = xmm6260_sec_modem_ipc_open(type); + if (transport_data->fd < 0) + return -1; + + return 0; +} + +int maguro_ipc_close(void *data) +{ + struct maguro_ipc_transport_data *transport_data; + + if (data == NULL) + return -1; + + transport_data = (struct maguro_ipc_transport_data *) data; + + xmm6260_sec_modem_ipc_close(transport_data->fd); + transport_data->fd = -1; + + return 0; +} + +int maguro_ipc_read(void *data, void *buffer, unsigned int length) +{ + struct maguro_ipc_transport_data *transport_data; + int rc; + + if (data == NULL) + return -1; + + transport_data = (struct maguro_ipc_transport_data *) data; + + rc = xmm6260_sec_modem_ipc_read(transport_data->fd, buffer, length); + return rc; +} + +int maguro_ipc_write(void *data, void *buffer, unsigned int length) +{ + struct maguro_ipc_transport_data *transport_data; + int rc; + + if (data == NULL) + return -1; + + transport_data = (struct maguro_ipc_transport_data *) data; + + rc = xmm6260_sec_modem_ipc_write(transport_data->fd, buffer, length); + return rc; +} + +int maguro_ipc_poll(void *data, struct timeval *timeout) +{ + struct maguro_ipc_transport_data *transport_data; + int rc; + + if (data == NULL) + return -1; + + transport_data = (struct maguro_ipc_transport_data *) data; + + rc = xmm6260_sec_modem_ipc_poll(transport_data->fd, timeout); + return rc; +} + +int maguro_ipc_power_on(void *data) +{ + return 0; +} + +int maguro_ipc_power_off(void *data) +{ + int fd; + int rc; + + fd = open(XMM6260_SEC_MODEM_BOOT0_DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK); + if (fd < 0) + return -1; + + rc = xmm6260_sec_modem_power(fd, 0); + + close(fd); + + if (rc < 0) + return -1; + + return 0; +} + +int maguro_ipc_data_create(void **transport_data, void **power_data, void **gprs_data) +{ + if (transport_data == NULL) + return -1; + + *transport_data = (void *) malloc(sizeof(struct maguro_ipc_transport_data)); + memset(*transport_data, 0, sizeof(struct maguro_ipc_transport_data)); + + return 0; +} + +int maguro_ipc_data_destroy(void *transport_data, void *power_data, void *gprs_data) +{ + if (transport_data == NULL) + return -1; + + free(transport_data); + + return 0; +} + +char *maguro_ipc_gprs_get_iface(int cid) +{ + return xmm6260_sec_modem_ipc_gprs_get_iface(cid); +} -#include "ipc.h" -#include "xmm6260_ipc.h" -#include "maguro_loader.h" +int maguro_ipc_gprs_get_capabilities(struct ipc_client_gprs_capabilities *capabilities) +{ + return xmm6260_sec_modem_ipc_gprs_get_capabilities(capabilities); +} struct ipc_ops maguro_ipc_fmt_ops = { .bootstrap = maguro_ipc_bootstrap, - .send = xmm6260_ipc_fmt_send, - .recv = xmm6260_ipc_fmt_recv, + .send = maguro_ipc_fmt_send, + .recv = maguro_ipc_fmt_recv, }; struct ipc_ops maguro_ipc_rfs_ops = { .bootstrap = NULL, - .send = xmm6260_ipc_rfs_send, - .recv = xmm6260_ipc_rfs_recv, + .send = maguro_ipc_rfs_send, + .recv = maguro_ipc_rfs_recv, }; struct ipc_handlers maguro_ipc_handlers = { - .open = xmm6260_ipc_open, - .close = xmm6260_ipc_close, - .read = xmm6260_ipc_read, - .write = xmm6260_ipc_write, - .poll = xmm6260_ipc_poll, + .read = maguro_ipc_read, + .write = maguro_ipc_write, + .open = maguro_ipc_open, + .close = maguro_ipc_close, + .poll = maguro_ipc_poll, .transport_data = NULL, - .power_on = xmm6260_ipc_power_on, - .power_off = xmm6260_ipc_power_off, + .power_on = maguro_ipc_power_on, + .power_off = maguro_ipc_power_off, .power_data = NULL, .gprs_activate = NULL, .gprs_deactivate = NULL, .gprs_data = NULL, - .data_create = xmm6260_ipc_data_create, - .data_destroy = xmm6260_ipc_data_destroy, + .data_create = maguro_ipc_data_create, + .data_destroy = maguro_ipc_data_destroy, }; struct ipc_gprs_specs maguro_ipc_gprs_specs = { - .gprs_get_iface = xmm6260_ipc_gprs_get_iface, - .gprs_get_capabilities = xmm6260_ipc_gprs_get_capabilities, + .gprs_get_iface = maguro_ipc_gprs_get_iface, + .gprs_get_capabilities = maguro_ipc_gprs_get_capabilities, }; struct ipc_nv_data_specs maguro_ipc_nv_data_specs = { - .nv_data_path = "/factory/nv_data.bin", - .nv_data_md5_path = "/factory/nv_data.bin.md5", - .nv_state_path = "/factory/.nv_state", - .nv_data_bak_path = "/factory/.nv_data.bak", - .nv_data_md5_bak_path = "/factory/.nv_data.bak.md5", + .nv_data_path = MAGURO_NV_DATA_PATH, + .nv_data_md5_path = MAGURO_NV_DATA_MD5_PATH, + .nv_state_path = MAGURO_NV_STATE_PATH, + .nv_data_bak_path = MAGURO_NV_DATA_BAK_PATH, + .nv_data_md5_bak_path = MAGURO_NV_DATA_MD5_BAK_PATH, }; // vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/device/maguro/maguro_ipc.h b/samsung-ipc/device/maguro/maguro_ipc.h new file mode 100644 index 0000000..eb4b500 --- /dev/null +++ b/samsung-ipc/device/maguro/maguro_ipc.h @@ -0,0 +1,52 @@ +/* + * 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 . + * + */ + +#ifndef __MAGURO_IPC_H__ +#define __MAGURO_IPC_H__ + +#define MAGURO_MODEM_IMAGE_SIZE 0x1000000 +#define MAGURO_PSI_OFFSET 0 +#define MAGURO_PSI_SIZE 0xF000 +#define MAGURO_EBL_OFFSET 0xF000 +#define MAGURO_EBL_SIZE 0x19000 +#define MAGURO_SEC_START_OFFSET 0x9FF800 +#define MAGURO_SEC_START_SIZE 0x800 +#define MAGURO_FIRMWARE_OFFSET 0x28000 +#define MAGURO_FIRMWARE_SIZE 0x9D8000 +#define MAGURO_NV_DATA_OFFSET 0xA00000 +#define MAGURO_NV_DATA_SIZE 0x200000 +#define MAGURO_MPS_DATA_SIZE 3 + +#define MAGURO_MODEM_IMAGE_DEVICE "/dev/block/platform/omap/omap_hsmmc.0/by-name/radio" +#define MAGURO_MPS_DATA_DEVICE "/factory/imei/mps_code.dat" + +#define MAGURO_NV_DATA_PATH "/factory/nv_data.bin" +#define MAGURO_NV_DATA_MD5_PATH "/factory/nv_data.bin.md5" +#define MAGURO_NV_STATE_PATH "/factory/.nv_state" +#define MAGURO_NV_DATA_BAK_PATH "/factory/.nv_data.bak" +#define MAGURO_NV_DATA_MD5_BAK_PATH "/factory/.nv_data.bak.md5" + +struct maguro_ipc_transport_data { + int fd; +}; + +#endif + +// vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/device/maguro/maguro_loader.c b/samsung-ipc/device/maguro/maguro_loader.c deleted file mode 100644 index 785585f..0000000 --- a/samsung-ipc/device/maguro/maguro_loader.c +++ /dev/null @@ -1,844 +0,0 @@ -/* - * Firmware loader for Samsung I9250 (maguro) - * 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 -#include - -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include "ipc.h" - -#include "maguro_loader.h" -#include "xmm6260_loader.h" -#include "xmm6260_modemctl.h" -#include "modem_prj.h" - -#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) - -/* - * Locations of the firmware components in the Samsung firmware - */ - -struct xmm6260_radio_part maguro_radio_parts[] = { - [PSI] = { - .offset = 0, - .length = 0xf000, - }, - [EBL] = { - .offset = 0xf000, - .length = 0x19000, - }, - [SECURE_IMAGE] = { - .offset = 0x9ff800, - .length = 0x800, - }, - [FIRMWARE] = { - .offset = 0x28000, - .length = 0x9d8000, - }, - [NVDATA] = { - .offset = 0xa00000, - .length = 2 << 20, - } -}; - -struct maguro_boot_cmd_desc maguro_boot_cmd_desc[] = { - [SetPortConf] = { - .code = 0x86, - .long_tail = 1, - }, - [ReqSecStart] = { - .code = 0x204, - .long_tail = 1, - }, - [ReqSecEnd] = { - .code = 0x205, - }, - [ReqForceHwReset] = { - .code = 0x208, - .long_tail = 1, - .no_ack = 1, - }, - [ReqFlashSetAddress] = { - .code = 0x802, - .long_tail = 1, - }, - [ReqFlashWriteBlock] = { - .code = 0x804, - }, -}; - -#define I9250_RADIO_IMAGE_PATHS_NUM 2 - -const char *i9250_radio_image_paths[] = { - "/dev/block/platform/omap/omap_hsmmc.0/by-name/radio", - "/dev/mmcblk0p9" -}; - -static int maguro_send_image(struct ipc_client *client, - struct modemctl_io_data *io_data, enum xmm6260_image type) -{ - int ret = -1; - - if (type >= ARRAY_SIZE(maguro_radio_parts)) { - ipc_client_log(client, "Error: bad image type %x", type); - goto fail; - } - - size_t length = maguro_radio_parts[type].length; - size_t offset = maguro_radio_parts[type].offset; - - size_t start = offset; - size_t end = length + start; - - unsigned char crc = xmm6260_crc_calculate(io_data->radio_data, offset, length); - - //dump some image bytes - ipc_client_log(client, "image start"); - - size_t chunk_size = 0xdfc; - - while (start < end) { - size_t remaining = end - start; - size_t curr_chunk = chunk_size < remaining ? chunk_size : remaining; - - ret = write(io_data->boot_fd, io_data->radio_data + start, curr_chunk); - - if (ret < 0) { - ipc_client_log(client, "Error: failed to write image chunk"); - goto fail; - } - - start += ret; - } - - ipc_client_log(client, "sent image type=%d", type); - - if (type == EBL) { - if ((ret = write(io_data->boot_fd, &crc, 1)) < 1) { - ipc_client_log(client, "Error: failed to write EBL CRC"); - goto fail; - } - else { - ipc_client_log(client, "wrote EBL CRC %02x", crc); - } - - goto done; - } - - uint32_t crc32 = (crc << 24) | 0xffffff; - - if ((ret = write(io_data->boot_fd, &crc32, 4)) != 4) { - ipc_client_log(client, "Error: failed to write CRC"); - goto fail; - } - else { - ipc_client_log(client, "wrote CRC %x", crc); - } - -done: - ret = 0; - -fail: - return ret; -} - -static int maguro_send_psi(struct ipc_client *client, - struct modemctl_io_data *io_data) -{ - int ret = -1; - - if ((ret = write(io_data->boot_fd, I9250_PSI_START_MAGIC, 4)) < 0) { - ipc_client_log(client, "%s: failed to write header, ret %d", __func__, ret); - goto fail; - } - - if ((ret = maguro_send_image(client, io_data, PSI)) < 0) { - ipc_client_log(client, "Error: failed to send PSI image"); - goto fail; - } - - char expected_acks[4][4] = { - "\xff\xff\xff\x01", - "\xff\xff\xff\x01", - "\x02\x00\x00\x00", - "\x01\xdd\x00\x00", - }; - - unsigned i; - for (i = 0; i < ARRAY_SIZE(expected_acks); i++) { - ret = expect_data(io_data->boot_fd, expected_acks[i], 4); - if (ret < 0) { - ipc_client_log(client, "failed to wait for ack %d", i); - goto fail; - } - } - ipc_client_log(client, "received PSI ACK"); - - return 0; - -fail: - return ret; -} - -static int maguro_send_ebl(struct ipc_client *client, - struct modemctl_io_data *io_data) -{ - int ret; - int fd = io_data->boot_fd; - unsigned length = maguro_radio_parts[EBL].length; - - if ((ret = write(fd, "\x04\x00\x00\x00", 4)) != 4) { - ipc_client_log(client, "Error: failed to write length of EBL length ('4') "); - goto fail; - } - - if ((ret = write(fd, &length, sizeof(length))) != sizeof(length)) { - ipc_client_log(client, "Error: failed to write EBL length"); - goto fail; - } - - if ((ret = expect_data(fd, I9250_GENERAL_ACK, 4)) < 0) { - ipc_client_log(client, "Error: failed to wait for EBL length ACK"); - goto fail; - } - - if ((ret = expect_data(fd, I9250_EBL_HDR_ACK_MAGIC, 4)) < 0) { - ipc_client_log(client, "Error: failed to wait for EBL header ACK"); - goto fail; - } - - length++; - if ((ret = write(fd, &length, sizeof(length))) != sizeof(length)) { - ipc_client_log(client, "Error: failed to write EBL length + 1"); - goto fail; - } - - if ((ret = maguro_send_image(client, io_data, EBL)) < 0) { - ipc_client_log(client, "Error: failed to send EBL image"); - goto fail; - } - else { - ipc_client_log(client, "sent EBL image, waiting for ACK"); - } - - if ((ret = expect_data(fd, I9250_GENERAL_ACK, 4)) < 0) { - ipc_client_log(client, "Error: failed to wait for EBL image general ACK"); - goto fail; - } - - if ((ret = expect_data(fd, I9250_EBL_IMG_ACK_MAGIC, 4)) < 0) { - ipc_client_log(client, "Error: failed to wait for EBL image ACK"); - goto fail; - } - else { - ipc_client_log(client, "got EBL ACK"); - } - - return 0; - -fail: - return ret; -} - -static int maguro_boot_cmd(struct ipc_client *client, - struct modemctl_io_data *io_data, enum xmm6260_boot_cmd cmd, - void *data, size_t data_size) -{ - int ret = 0; - char *cmd_data = 0; - uint32_t ack_length; - - if (cmd >= ARRAY_SIZE(maguro_boot_cmd_desc)) { - ipc_client_log(client, "Error: bad command %x\n", cmd); - goto done_or_fail; - } - - unsigned cmd_code = maguro_boot_cmd_desc[cmd].code; - uint16_t checksum = (data_size & 0xffff) + cmd_code; - unsigned char *ptr = (unsigned char*)data; - size_t i; - - for (i = 0; i < data_size; i++) { - checksum += ptr[i]; - } - - DECLARE_BOOT_CMD_HEADER(header, cmd_code, data_size); - DECLARE_BOOT_TAIL_HEADER(tail, checksum); - - size_t tail_size = sizeof(tail); - if (!maguro_boot_cmd_desc[cmd].long_tail) { - tail_size -= 2; - } - - size_t cmd_buffer_size = data_size + sizeof(header) + tail_size; - ipc_client_log(client, "data_size %d [%d] checksum 0x%x", data_size, cmd_buffer_size, checksum); - - cmd_data = (char*)malloc(cmd_buffer_size); - - if (!cmd_data) { - ipc_client_log(client, "Error: failed to allocate command buffer"); - ret = -ENOMEM; - goto done_or_fail; - } - - memset(cmd_data, 0, cmd_buffer_size); - memcpy(cmd_data, &header, sizeof(header)); - memcpy(cmd_data + sizeof(header), data, data_size); - memcpy(cmd_data + sizeof(header) + data_size, &tail, tail_size); - - if ((ret = write(io_data->boot_fd, cmd_data, cmd_buffer_size)) < 0) { - ipc_client_log(client, "Error: failed to write command to socket"); - goto done_or_fail; - } - - if ((unsigned)ret < cmd_buffer_size) { - ipc_client_log(client, "Error: written %d bytes of %d", ret, cmd_buffer_size); - ret = -EINVAL; - goto done_or_fail; - } - - if (maguro_boot_cmd_desc[cmd].no_ack) { - ipc_client_log(client, "not waiting for ACK"); - goto done_or_fail; - } - - if ((ret = expect_read(io_data->boot_fd, &ack_length, 4)) < 0) { - ipc_client_log(client, "Error: failed to receive ack header length"); - goto done_or_fail; - } - - if (ack_length + 4 > cmd_buffer_size) { - free(cmd_data); - - cmd_data = NULL; - cmd_data = malloc(ack_length + 4); - - if (!cmd_data) { - ipc_client_log(client, "Error: failed to allocate the buffer for ack data"); - goto done_or_fail; - } - } - - memset(cmd_data, 0, ack_length); - memcpy(cmd_data, &ack_length, 4); - - for (i = 0; i < (ack_length + 3) / 4; i++) { - if ((ret = expect_read(io_data->boot_fd, cmd_data + ((i + 1) << 2), 4)) < 0) { - ipc_client_log(client, "Error: failed to receive ack chunk"); - goto done_or_fail; - } - } - - ipc_client_log(client, "received ack"); - - struct maguro_boot_cmd_header *ack_hdr = (struct maguro_boot_cmd_header*)cmd_data; - struct maguro_boot_tail_header *ack_tail = (struct maguro_boot_tail_header*) - (cmd_data + ack_length + 4 - sizeof(struct maguro_boot_tail_header)); - - ipc_client_log(client, "ack code 0x%x checksum 0x%x", ack_hdr->cmd, ack_tail->checksum); - if (ack_hdr->cmd != header.cmd) { - ipc_client_log(client, "Error: request and ack command codes do not match"); - ret = -1; - goto done_or_fail; - } - - ret = 0; - -done_or_fail: - if (cmd_data) - free(cmd_data); - - return ret; -} - -static int maguro_boot_info_ack(struct ipc_client *client, - struct modemctl_io_data *io_data) -{ - int ret = -1; - uint32_t boot_info_length; - char *boot_info = 0; - - - if ((ret = expect_read(io_data->boot_fd, &boot_info_length, 4)) < 0) { - ipc_client_log(client, "Error: failed to receive boot info length"); - goto fail; - } - - ipc_client_log(client, "Boot Info length=0x%x", boot_info_length); - - boot_info = (char*)malloc(boot_info_length); - if (!boot_info) { - ipc_client_log(client, "Error: failed to allocate memory for boot info"); - goto fail; - } - - memset(boot_info, 0, boot_info_length); - - size_t boot_chunk = 4; - size_t boot_chunk_count = (boot_info_length + boot_chunk - 1) / boot_chunk; - unsigned i; - for (i = 0; i < boot_chunk_count; i++) { - ret = expect_read(io_data->boot_fd, boot_info + (i * boot_chunk), boot_chunk); - if (ret < 0) { - ipc_client_log(client, "Error: failed to receive Boot Info chunk %i ret=%d", i, ret); - goto fail; - } - } - - ipc_client_log(client, "received Boot Info"); - - ret = maguro_boot_cmd(client, io_data, SetPortConf, boot_info, boot_info_length); - if (ret < 0) { - ipc_client_log(client, "Error: failed to send SetPortConf command"); - goto fail; - } - else { - ipc_client_log(client, "sent SetPortConf command"); - } - - ret = 0; - -fail: - if (boot_info) - free(boot_info); - - return ret; -} - -static int maguro_send_image_data(struct ipc_client *client, - struct modemctl_io_data *io_data, uint32_t addr, - void *data, int data_len) -{ - int ret = 0; - int count = 0; - char *data_p = (char *) data; - - if ((ret = maguro_boot_cmd(client, io_data, ReqFlashSetAddress, &addr, 4)) < 0) { - ipc_client_log(client, "Error: failed to send ReqFlashSetAddress"); - goto fail; - } - else { - ipc_client_log(client, "sent ReqFlashSetAddress"); - } - - while (count < data_len) { - int rest = data_len - count; - int chunk = rest < SEC_DOWNLOAD_CHUNK ? rest : SEC_DOWNLOAD_CHUNK; - - ret = maguro_boot_cmd(client, io_data, ReqFlashWriteBlock, data_p, chunk); - if (ret < 0) { - ipc_client_log(client, "Error: failed to send data chunk"); - goto fail; - } - - data_p += chunk; - count += chunk; - } - - usleep(SEC_DOWNLOAD_DELAY_US); - -fail: - return ret; -} - -static int maguro_send_image_addr(struct ipc_client *client, - struct modemctl_io_data *io_data, uint32_t addr, enum xmm6260_image type) -{ - uint32_t offset = maguro_radio_parts[type].offset; - uint32_t length = maguro_radio_parts[type].length; - char *start = io_data->radio_data + offset; - int ret = 0; - - ret = maguro_send_image_data(client, io_data, addr, start, length); - - return ret; -} - -static int maguro_send_mps_data(struct ipc_client *client, - struct modemctl_io_data *io_data) -{ - int ret = 0; - int mps_fd = -1; - char mps_data[I9250_MPS_LENGTH] = {}; - uint32_t addr = I9250_MPS_LOAD_ADDR; - - mps_fd = open(I9250_MPS_IMAGE_PATH, O_RDONLY); - if (mps_fd < 0) { - ipc_client_log(client, "Error: failed to open MPS data"); - goto fail; - } - else { - ret = read(mps_fd, mps_data, I9250_MPS_LENGTH); - if (ret < 0) { - ipc_client_log(client, "Error: failed to read MPS data\n"); - goto fail; - } - } - - if ((ret = maguro_boot_cmd(client, io_data, ReqFlashSetAddress, &addr, 4)) < 0) { - ipc_client_log(client, "Error: failed to send ReqFlashSetAddress"); - goto fail; - } - else { - ipc_client_log(client, "sent ReqFlashSetAddress"); - } - - if ((ret = maguro_boot_cmd(client, io_data, ReqFlashWriteBlock, - mps_data, I9250_MPS_LENGTH)) < 0) { - ipc_client_log(client, "Error: failed to write MPS data to modem"); - goto fail; - } - - -fail: - if (mps_fd >= 0) - close(mps_fd); - - return ret; -} - -static int maguro_send_image_addrs(struct ipc_client *client, - struct modemctl_io_data *io_data) -{ - int ret = 0; - - uint32_t sec_off = maguro_radio_parts[SECURE_IMAGE].offset; - uint32_t sec_len = maguro_radio_parts[SECURE_IMAGE].length; - void *sec_img = io_data->radio_data + sec_off; - void *nv_data = NULL; - - if ((ret = maguro_boot_cmd(client, io_data, ReqSecStart, sec_img, sec_len)) < 0) { - ipc_client_log(client, "Error: failed to write ReqSecStart"); - goto fail; - } - else { - ipc_client_log(client, "sent ReqSecStart"); - } - - if ((ret = maguro_send_image_addr(client, io_data, FW_LOAD_ADDR, FIRMWARE)) < 0) { - ipc_client_log(client, "Error: failed to send FIRMWARE image"); - goto fail; - } - else { - ipc_client_log(client, "sent FIRMWARE image"); - } - - if (nv_data_check(client) < 0) - goto fail; - - if (nv_data_md5_check(client) < 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, "Error: failed to read NVDATA image"); - goto fail; - } - - if ((ret = maguro_send_image_data(client, io_data, NVDATA_LOAD_ADDR, nv_data, 2 << 20)) < 0) { - ipc_client_log(client, "Error: failed to send NVDATA image"); - goto fail; - } - else { - ipc_client_log(client, "sent NVDATA image"); - } - - free(nv_data); - - if ((ret = maguro_send_mps_data(client, io_data)) < 0) { - ipc_client_log(client, "Error: failed to send MPS data"); - goto fail; - } - else { - ipc_client_log(client, "sent MPS data"); - } - - if ((ret = maguro_boot_cmd(client, io_data, ReqSecEnd, - BL_END_MAGIC, BL_END_MAGIC_LEN)) < 0) - { - ipc_client_log(client, "Error: failed to write ReqSecEnd"); - goto fail; - } - else { - ipc_client_log(client, "sent ReqSecEnd"); - } - - ret = maguro_boot_cmd(client, io_data, ReqForceHwReset, - BL_RESET_MAGIC, BL_RESET_MAGIC_LEN); - if (ret < 0) { - ipc_client_log(client, "Error: failed to write ReqForceHwReset"); - goto fail; - } - else { - ipc_client_log(client, "sent ReqForceHwReset"); - } - -fail: - return ret; -} - -static int maguro_modem_reboot(struct ipc_client *client, - struct modemctl_io_data *io_data, bool hard) -{ - int ret; - - if (!hard) - return 0; - - /* Disable the hardware to ensure consistent state */ - if ((ret = modemctl_modem_power(client, io_data, false)) < 0) { - ipc_client_log(client, "Error: failed to disable modem power"); - goto fail; - } - else { - ipc_client_log(client, "disabled modem power"); - } - - /* Now, initialize the hardware */ - if ((ret = modemctl_modem_power(client, io_data, true)) < 0) { - ipc_client_log(client, "Error: failed to enable modem power"); - goto fail; - } - else { - ipc_client_log(client, "enabled modem power"); - } - -fail: - return ret; -} - -int maguro_ipc_power_off(void *io_data_unused) { - int ret = -1; - struct modemctl_io_data io_data; - - io_data.boot_fd = open(BOOT_DEV, O_RDWR | O_NOCTTY | O_NONBLOCK); - if (io_data.boot_fd < 0) { - ret = io_data.boot_fd; - goto fail; - } - - if ((ret = modemctl_modem_power(NULL, &io_data, false)) < 0) - goto fail_pwr; - - ret = 0; - -fail_pwr: - close(io_data.boot_fd); -fail: - return ret; -} - -int maguro_ipc_bootstrap(struct ipc_client *client) -{ - int ret = -1, n = 0, fd = -1, i; - struct modemctl_io_data io_data; - memset(&io_data, 0, sizeof(client, io_data)); - - io_data.radio_fd = -1; - for (n = 0; n < I9250_RADIO_IMAGE_PATHS_NUM; n++) { - fd = open(i9250_radio_image_paths[n], O_RDONLY); - if (fd > 0) { - io_data.radio_fd = fd; - ipc_client_log(client, "opened radio image %s, fd=%d", i9250_radio_image_paths[n], io_data.radio_fd); - break; - } - } - - if (io_data.radio_fd < 0) { - ipc_client_log(client, "Error: failed to open radio firmware"); - goto fail; - } - - if (fstat(io_data.radio_fd, &io_data.radio_stat) < 0) { - ipc_client_log(client, "Error: failed to stat radio image, error %s", strerror(errno)); - 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, "Error: failed to mmap radio image, error %s", strerror(errno)); - goto fail; - } - - io_data.boot_fd = open(BOOT_DEV, O_RDWR | O_NOCTTY | O_NONBLOCK); - if (io_data.boot_fd < 0) { - ipc_client_log(client, "Error: failed to open boot device"); - goto fail; - } - else { - ipc_client_log(client, "opened boot device %s, fd=%d", BOOT_DEV, io_data.boot_fd); - } - - if (maguro_modem_reboot(client, &io_data, true) < 0) { - ipc_client_log(client, "Error: failed to hard reset modem"); - goto fail; - } - else { - ipc_client_log(client, "modem hard reset done"); - } - - /* Now, actually load the firmware */ - for (i = 0; i < 2; i++) { - if (write(io_data.boot_fd, "ATAT", 4) != 4) { - ipc_client_log(client, "Error: failed to write ATAT to boot socket"); - goto fail; - } - else { - ipc_client_log(client, "written ATAT to boot socket, waiting for ACK"); - } - - if (expect(io_data.boot_fd, 100) < 0) { - ipc_client_log(client, "failed to select before next ACK, ignoring"); - } - } - - /* FIXME: make sure it does not timeout or add the retry in the ril library */ - if ((ret = expect(io_data.boot_fd, 100)) < 0) { - ipc_client_log(client, "Error: failed to wait for bootloader ready state"); - goto fail; - } - else { - ipc_client_log(client, "ready for PSI upload"); - } - - ret = -ETIMEDOUT; - for (i = 0; i < I9250_BOOT_REPLY_MAX; i++) { - uint32_t id_buf; - if ((ret = expect_read(io_data.boot_fd, (void*)&id_buf, 4)) != 4) { - ipc_client_log(client, "Error: failed receiving bootloader reply"); - goto fail; - } - ipc_client_log(client, "got bootloader reply %08x", id_buf); - if ((id_buf & I9250_BOOT_LAST_MASK) == I9250_BOOT_LAST_MASK) { - ret = 0; - break; - } - } - - if (ret < 0) { - ipc_client_log(client, "Error: bootloader id marker not received"); - goto fail; - } - else { - ipc_client_log(client, "got bootloader id marker"); - } - - if ((ret = maguro_send_psi(client, &io_data)) < 0) { - ipc_client_log(client, "Error: failed to upload PSI"); - goto fail; - } - else { - ipc_client_log(client, "PSI download complete"); - } - - close(io_data.boot_fd); - io_data.boot_fd = open(I9250_SECOND_BOOT_DEV, O_RDWR | O_NOCTTY | O_NONBLOCK); - if (io_data.boot_fd < 0) { - ipc_client_log(client, "Error: failed to open " I9250_SECOND_BOOT_DEV " control device"); - goto fail; - } - else { - ipc_client_log(client, "opened second boot device %s, fd=%d", I9250_SECOND_BOOT_DEV, io_data.boot_fd); - } - - if ((ret = write(io_data.boot_fd, I9250_PSI_CMD_EXEC, 4)) < 0) { - ipc_client_log(client, "Error: failed writing cmd_load_exe_EBL"); - goto fail; - } - - if ((ret = write(io_data.boot_fd, I9250_PSI_EXEC_DATA, 8)) < 0) { - ipc_client_log(client, "Error: failed writing 8 bytes to boot1"); - goto fail; - } - - if ((ret = expect_data(io_data.boot_fd, I9250_GENERAL_ACK, 4)) < 0) { - ipc_client_log(client, "Error: failed to receive cmd_load_exe_EBL ack"); - goto fail; - } - - if ((ret = expect_data(io_data.boot_fd, I9250_PSI_READY_ACK, 4)) < 0) { - ipc_client_log(client, "Error: failed to receive PSI ready ack"); - goto fail; - } - - if ((ret = maguro_send_ebl(client, &io_data)) < 0) { - ipc_client_log(client, "Error: failed to upload EBL"); - goto fail; - } - else { - ipc_client_log(client, "EBL download complete"); - } - - if ((ret = maguro_boot_info_ack(client, &io_data)) < 0) { - ipc_client_log(client, "Error: failed to receive Boot Info"); - goto fail; - } - else { - ipc_client_log(client, "Boot Info ACK done"); - } - - if ((ret = maguro_send_image_addrs(client, &io_data)) < 0) { - ipc_client_log(client, "Error: failed to upload Secure Image"); - goto fail; - } - else { - ipc_client_log(client, "Secure Image download complete"); - } - - if ((ret = modemctl_wait_modem_online(client, &io_data))) { - ipc_client_log(client, "Error: failed to wait for modem to become online"); - goto fail; - } - - /* This restores UART MUX to GPS */ - modemctl_modem_boot_power(client, &io_data, false); - - ipc_client_log(client, "Modem is online!"); - ret = 0; - -fail: - if (io_data.radio_data != MAP_FAILED) - munmap(io_data.radio_data, RADIO_MAP_SIZE); - - if (io_data.radio_fd >= 0) - close(io_data.radio_fd); - - if (io_data.boot_fd >= 0) - close(io_data.boot_fd); - - return ret; -} - -// vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/device/maguro/maguro_loader.h b/samsung-ipc/device/maguro/maguro_loader.h deleted file mode 100644 index 2f97133..0000000 --- a/samsung-ipc/device/maguro/maguro_loader.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Firmware loader for Samsung I9250 (maguro) - * 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 __MAGURO_LOADER_H__ -#define __MAGURO_LOADER_H__ - -#define I9250_SECOND_BOOT_DEV "/dev/umts_boot1" - -#define I9250_BOOT_LAST_MASK 0x0000ffff -#define I9250_BOOT_REPLY_MAX 20 - -#define I9250_GENERAL_ACK "\x02\x00\x00\x00" - -#define I9250_PSI_START_MAGIC "\xff\xf0\x00\x30" -#define I9250_PSI_CMD_EXEC "\x08\x00\x00\x00" -#define I9250_PSI_EXEC_DATA "\x00\x00\x00\x00\x02\x00\x02\x00" -#define I9250_PSI_READY_ACK "\x00\xaa\x00\x00" - -#define I9250_EBL_IMG_ACK_MAGIC "\x51\xa5\x00\x00" -#define I9250_EBL_HDR_ACK_MAGIC "\xcc\xcc\x00\x00" - -#define I9250_MPS_IMAGE_PATH "/factory/imei/mps_code.dat" -#define I9250_MPS_LOAD_ADDR 0x61080000 -#define I9250_MPS_LENGTH 3 - -#define SEC_DOWNLOAD_CHUNK 0xdfc2 -#define SEC_DOWNLOAD_DELAY_US (500 * 1000) - - #define FW_LOAD_ADDR 0x60300000 -#define NVDATA_LOAD_ADDR 0x60e80000 - -#define BL_END_MAGIC "\x00\x00" -#define BL_END_MAGIC_LEN 2 - -#define BL_RESET_MAGIC "\x01\x10\x11\x00" -#define BL_RESET_MAGIC_LEN 4 - -/* - * on I9250, all commands need ACK and we do not need to - * allocate a fixed size buffer - */ -struct maguro_boot_cmd_desc { - unsigned code; - bool long_tail; - bool no_ack; -}; - -struct maguro_boot_cmd_header { - uint32_t total_size; - uint16_t hdr_magic; - uint16_t cmd; - uint16_t data_size; -} __attribute__((packed)); - -#define DECLARE_BOOT_CMD_HEADER(name, code, size) \ -struct maguro_boot_cmd_header name = {\ - .total_size = size + 10,\ - .hdr_magic = 2,\ - .cmd = code,\ - .data_size = size,\ -} - -struct maguro_boot_tail_header { - uint16_t checksum; - uint16_t tail_magic; - uint8_t unknown[2]; -} __attribute__((packed)); - -#define DECLARE_BOOT_TAIL_HEADER(name, checksum) \ -struct maguro_boot_tail_header name = {\ - .checksum = checksum,\ - .tail_magic = 3,\ - .unknown = "\xea\xea",\ -} - -int maguro_ipc_bootstrap(struct ipc_client *client); -int maguro_ipc_power_off(void *io_data); - -#endif - -// vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/device/piranha/piranha_ipc.c b/samsung-ipc/device/piranha/piranha_ipc.c index 17b7133..5bdd0cd 100644 --- a/samsung-ipc/device/piranha/piranha_ipc.c +++ b/samsung-ipc/device/piranha/piranha_ipc.c @@ -1,4 +1,4 @@ -/** +/* * This file is part of libsamsung-ipc. * * Copyright (C) 2013 Paul Kocialkowski @@ -18,44 +18,341 @@ */ #include +#include +#include +#include +#include -#include "ipc.h" +#include +#include -#include "xmm6260_ipc.h" -#include "piranha_loader.h" +#include "xmm6260.h" +#include "xmm6260_mipi.h" +#include "xmm6260_sec_modem.h" +#include "piranha_ipc.h" + +int piranha_ipc_bootstrap(struct ipc_client *client) +{ + void *modem_image_data = NULL; + int modem_image_fd = -1; + int modem_boot_fd = -1; + + unsigned char *p; + int rc; + + if (client == NULL) + return -1; + + ipc_client_log(client, "Starting piranha modem bootstrap"); + + modem_image_fd = open(PIRANHA_MODEM_IMAGE_DEVICE, O_RDONLY); + if (modem_image_fd < 0) { + ipc_client_log(client, "Opening modem image device failed"); + goto error; + } + ipc_client_log(client, "Opened modem image device"); + + modem_image_data = mmap(0, PIRANHA_MODEM_IMAGE_SIZE, PROT_READ, MAP_SHARED, modem_image_fd, 0); + if (modem_image_data == NULL || modem_image_data == (void *) 0xffffffff) { + ipc_client_log(client, "Mapping modem image data to memory failed"); + goto error; + } + ipc_client_log(client, "Mapped modem image data to memory"); + + modem_boot_fd = open(XMM6260_SEC_MODEM_BOOT0_DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK); + if (modem_boot_fd < 0) { + ipc_client_log(client, "Opening modem boot device failed"); + goto error; + } + ipc_client_log(client, "Opened modem boot device"); + + rc = xmm6260_sec_modem_power(modem_boot_fd, 0); + if (rc < 0) { + ipc_client_log(client, "Turning the modem off failed"); + goto error; + } + ipc_client_log(client, "Turned the modem off"); + + rc = xmm6260_sec_modem_power(modem_boot_fd, 1); + if (rc < 0) { + ipc_client_log(client, "Turning the modem on failed"); + goto error; + } + ipc_client_log(client, "Turned the modem on"); + + p = (unsigned char *) modem_image_data + PIRANHA_PSI_OFFSET; + + rc = xmm6260_mipi_psi_send(client, modem_boot_fd, (void *) p, PIRANHA_PSI_SIZE); + if (rc < 0) { + ipc_client_log(client, "Sending XMM6260 MIPI PSI failed"); + goto error; + } + ipc_client_log(client, "Sent XMM6260 MIPI PSI"); + + close(modem_boot_fd); + + modem_boot_fd = open(XMM6260_SEC_MODEM_BOOT1_DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK); + if (modem_boot_fd < 0) { + ipc_client_log(client, "Opening modem boot device failed"); + goto error; + } + ipc_client_log(client, "Opened modem boot device"); + + p = (unsigned char *) modem_image_data + PIRANHA_EBL_OFFSET; + + rc = xmm6260_mipi_ebl_send(client, modem_boot_fd, (void *) p, PIRANHA_EBL_SIZE); + if (rc < 0) { + ipc_client_log(client, "Sending XMM6260 MIPI EBL failed"); + goto error; + } + ipc_client_log(client, "Sent XMM6260 MIPI EBL"); + + rc = xmm6260_mipi_port_config_send(client, modem_boot_fd); + if (rc < 0) { + ipc_client_log(client, "Sending XMM6260 MIPI port config failed"); + goto error; + } + ipc_client_log(client, "Sent XMM6260 MIPI port config"); + + p = (unsigned char *) modem_image_data + PIRANHA_SEC_START_OFFSET; + + rc = xmm6260_mipi_sec_start_send(client, modem_boot_fd, (void *) p, PIRANHA_SEC_START_SIZE); + if (rc < 0) { + ipc_client_log(client, "Sending XMM6260 MIPI SEC start failed"); + goto error; + } + ipc_client_log(client, "Sent XMM6260 MIPI SEC start"); + + p = (unsigned char *) modem_image_data + PIRANHA_FIRMWARE_OFFSET; + + rc = xmm6260_mipi_firmware_send(client, modem_boot_fd, (void *) p, PIRANHA_FIRMWARE_SIZE); + if (rc < 0) { + ipc_client_log(client, "Sending XMM6260 MIPI firmware failed"); + goto error; + } + ipc_client_log(client, "Sent XMM6260 MIPI firmware"); + + rc = xmm6260_mipi_nv_data_send(client, modem_boot_fd); + if (rc < 0) { + ipc_client_log(client, "Sending XMM6260 MIPI nv_data failed"); + goto error; + } + ipc_client_log(client, "Sent XMM6260 MIPI nv_data"); + + rc = xmm6260_mipi_sec_end_send(client, modem_boot_fd); + if (rc < 0) { + ipc_client_log(client, "Sending XMM6260 MIPI SEC end failed"); + goto error; + } + ipc_client_log(client, "Sent XMM6260 MIPI SEC end"); + + rc = xmm6260_mipi_hw_reset_send(client, modem_boot_fd); + if (rc < 0) { + ipc_client_log(client, "Sending XMM6260 MIPI HW reset failed"); + goto error; + } + ipc_client_log(client, "Sent XMM6260 MIPI HW reset"); + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + if (modem_image_data != NULL) + munmap(modem_image_data, PIRANHA_MODEM_IMAGE_SIZE); + + if (modem_image_fd >= 0) + close(modem_image_fd); + + if (modem_boot_fd >= 0) + close(modem_boot_fd); + + return rc; +} + +int piranha_ipc_fmt_send(struct ipc_client *client, struct ipc_message_info *request) +{ + return xmm6260_sec_modem_ipc_fmt_send(client, request); +} + +int piranha_ipc_fmt_recv(struct ipc_client *client, struct ipc_message_info *response) +{ + return xmm6260_sec_modem_ipc_fmt_recv(client, response); +} + +int piranha_ipc_rfs_send(struct ipc_client *client, struct ipc_message_info *request) +{ + return xmm6260_sec_modem_ipc_rfs_send(client, request); +} + +int piranha_ipc_rfs_recv(struct ipc_client *client, struct ipc_message_info *response) +{ + return xmm6260_sec_modem_ipc_rfs_recv(client, response); +} + +int piranha_ipc_open(void *data, int type) +{ + struct piranha_ipc_transport_data *transport_data; + + if (data == NULL) + return -1; + + transport_data = (struct piranha_ipc_transport_data *) data; + + transport_data->fd = xmm6260_sec_modem_ipc_open(type); + if (transport_data->fd < 0) + return -1; + + return 0; +} + +int piranha_ipc_close(void *data) +{ + struct piranha_ipc_transport_data *transport_data; + + if (data == NULL) + return -1; + + transport_data = (struct piranha_ipc_transport_data *) data; + + xmm6260_sec_modem_ipc_close(transport_data->fd); + transport_data->fd = -1; + + return 0; +} + +int piranha_ipc_read(void *data, void *buffer, unsigned int length) +{ + struct piranha_ipc_transport_data *transport_data; + int rc; + + if (data == NULL) + return -1; + + transport_data = (struct piranha_ipc_transport_data *) data; + + rc = xmm6260_sec_modem_ipc_read(transport_data->fd, buffer, length); + return rc; +} + +int piranha_ipc_write(void *data, void *buffer, unsigned int length) +{ + struct piranha_ipc_transport_data *transport_data; + int rc; + + if (data == NULL) + return -1; + + transport_data = (struct piranha_ipc_transport_data *) data; + + rc = xmm6260_sec_modem_ipc_write(transport_data->fd, buffer, length); + return rc; +} + +int piranha_ipc_poll(void *data, struct timeval *timeout) +{ + struct piranha_ipc_transport_data *transport_data; + int rc; + + if (data == NULL) + return -1; + + transport_data = (struct piranha_ipc_transport_data *) data; + + rc = xmm6260_sec_modem_ipc_poll(transport_data->fd, timeout); + return rc; +} + +int piranha_ipc_power_on(void *data) +{ + return 0; +} + +int piranha_ipc_power_off(void *data) +{ + int fd; + int rc; + + fd = open(XMM6260_SEC_MODEM_BOOT0_DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK); + if (fd < 0) + return -1; + + rc = xmm6260_sec_modem_power(fd, 0); + + close(fd); + + if (rc < 0) + return -1; + + return 0; +} + +int piranha_ipc_data_create(void **transport_data, void **power_data, void **gprs_data) +{ + if (transport_data == NULL) + return -1; + + *transport_data = (void *) malloc(sizeof(struct piranha_ipc_transport_data)); + memset(*transport_data, 0, sizeof(struct piranha_ipc_transport_data)); + + return 0; +} + +int piranha_ipc_data_destroy(void *transport_data, void *power_data, void *gprs_data) +{ + if (transport_data == NULL) + return -1; + + free(transport_data); + + return 0; +} + +char *piranha_ipc_gprs_get_iface(int cid) +{ + return xmm6260_sec_modem_ipc_gprs_get_iface(cid); +} + + +int piranha_ipc_gprs_get_capabilities(struct ipc_client_gprs_capabilities *capabilities) +{ + return xmm6260_sec_modem_ipc_gprs_get_capabilities(capabilities); +} struct ipc_ops piranha_ipc_fmt_ops = { - .bootstrap = piranha_modem_bootstrap, - .send = xmm6260_ipc_fmt_send, - .recv = xmm6260_ipc_fmt_recv, + .bootstrap = piranha_ipc_bootstrap, + .send = piranha_ipc_fmt_send, + .recv = piranha_ipc_fmt_recv, }; struct ipc_ops piranha_ipc_rfs_ops = { .bootstrap = NULL, - .send = xmm6260_ipc_rfs_send, - .recv = xmm6260_ipc_rfs_recv, + .send = piranha_ipc_rfs_send, + .recv = piranha_ipc_rfs_recv, }; struct ipc_handlers piranha_ipc_handlers = { - .read = xmm6260_ipc_read, - .write = xmm6260_ipc_write, - .open = xmm6260_ipc_open, - .close = xmm6260_ipc_close, - .poll = xmm6260_ipc_poll, + .read = piranha_ipc_read, + .write = piranha_ipc_write, + .open = piranha_ipc_open, + .close = piranha_ipc_close, + .poll = piranha_ipc_poll, .transport_data = NULL, - .power_on = xmm6260_ipc_power_on, - .power_off = xmm6260_ipc_power_off, + .power_on = piranha_ipc_power_on, + .power_off = piranha_ipc_power_off, .power_data = NULL, .gprs_activate = NULL, .gprs_deactivate = NULL, .gprs_data = NULL, - .data_create = xmm6260_ipc_data_create, - .data_destroy = xmm6260_ipc_data_destroy, + .data_create = piranha_ipc_data_create, + .data_destroy = piranha_ipc_data_destroy, }; struct ipc_gprs_specs piranha_ipc_gprs_specs = { - .gprs_get_iface = xmm6260_ipc_gprs_get_iface, - .gprs_get_capabilities = xmm6260_ipc_gprs_get_capabilities, + .gprs_get_iface = piranha_ipc_gprs_get_iface, + .gprs_get_capabilities = piranha_ipc_gprs_get_capabilities, }; // vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/device/piranha/piranha_ipc.h b/samsung-ipc/device/piranha/piranha_ipc.h new file mode 100644 index 0000000..f915297 --- /dev/null +++ b/samsung-ipc/device/piranha/piranha_ipc.h @@ -0,0 +1,44 @@ +/* + * 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 . + * + */ + +#ifndef __PIRANHA_IPC_H__ +#define __PIRANHA_IPC_H__ + +#define PIRANHA_MODEM_IMAGE_SIZE 0x1400000 +#define PIRANHA_PSI_OFFSET 0x1000 +#define PIRANHA_PSI_SIZE 0xE000 +#define PIRANHA_EBL_OFFSET 0xF000 +#define PIRANHA_EBL_SIZE 0x19000 +#define PIRANHA_SEC_START_OFFSET 0x9FF800 +#define PIRANHA_SEC_START_SIZE 0x800 +#define PIRANHA_FIRMWARE_OFFSET 0x28000 +#define PIRANHA_FIRMWARE_SIZE 0x9D7800 +#define PIRANHA_NV_DATA_OFFSET 0xA00000 +#define PIRANHA_NV_DATA_SIZE 0x200000 + +#define PIRANHA_MODEM_IMAGE_DEVICE "/dev/block/mmcblk0p8" + +struct piranha_ipc_transport_data { + int fd; +}; + +#endif + +// vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/device/piranha/piranha_loader.c b/samsung-ipc/device/piranha/piranha_loader.c deleted file mode 100644 index d5b28ad..0000000 --- a/samsung-ipc/device/piranha/piranha_loader.c +++ /dev/null @@ -1,764 +0,0 @@ -/* - * 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.h" - -#include "xmm6260_loader.h" -#include "xmm6260_modemctl.h" - -#include "piranha_loader.h" - -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 deleted file mode 100644 index bf874f8..0000000 --- a/samsung-ipc/device/piranha/piranha_loader.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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/device/xmm6260/modem.h b/samsung-ipc/device/xmm6260/modem.h new file mode 100644 index 0000000..5a456f5 --- /dev/null +++ b/samsung-ipc/device/xmm6260/modem.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2010 Google, Inc. + * Copyright (C) 2010 Samsung Electronics. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef __MODEM_IF_H__ +#define __MODEM_IF_H__ + +enum modem_t { + IMC_XMM6260, + IMC_XMM6262, + VIA_CBP71, + VIA_CBP72, + SEC_CMC221, + QC_MDM6600, + DUMMY, +}; + +enum dev_format { + IPC_FMT, + IPC_RAW, + IPC_RFS, + IPC_CMD, + IPC_BOOT, + IPC_MULTI_RAW, + IPC_RAMDUMP, + MAX_DEV_FORMAT, +}; +#define MAX_IPC_DEV (IPC_RFS + 1) + +enum modem_io { + IODEV_MISC, + IODEV_NET, + IODEV_DUMMY, +}; + +enum modem_link { + LINKDEV_UNDEFINED, + LINKDEV_MIPI, + LINKDEV_DPRAM, + LINKDEV_SPI, + LINKDEV_USB, + LINKDEV_HSIC, + LINKDEV_C2C, + LINKDEV_MAX, +}; +#define LINKTYPE(modem_link) (1u << (modem_link)) + +enum modem_network { + UMTS_NETWORK, + CDMA_NETWORK, + LTE_NETWORK, +}; + +enum sipc_ver { + NO_SIPC_VER = 0, + SIPC_VER_40 = 40, + SIPC_VER_41 = 41, + SIPC_VER_42 = 42, + SIPC_VER_50 = 50, + MAX_SIPC_VER, +}; + +#endif diff --git a/samsung-ipc/device/xmm6260/modem_link_device_hsic.h b/samsung-ipc/device/xmm6260/modem_link_device_hsic.h new file mode 100755 index 0000000..99e15cf --- /dev/null +++ b/samsung-ipc/device/xmm6260/modem_link_device_hsic.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2010 Google, Inc. + * Copyright (C) 2010 Samsung Electronics. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef __MODEM_LINK_DEVICE_USB_H__ +#define __MODEM_LINK_DEVICE_USB_H__ + + +enum { + IF_USB_BOOT_EP = 0, + IF_USB_FMT_EP = 0, + IF_USB_RAW_EP, + IF_USB_RFS_EP, + IF_USB_CMD_EP, + IF_USB_DEVNUM_MAX, +}; + +/* each pipe has 2 ep for in/out */ +#define LINKPM_DEV_NUM (IF_USB_DEVNUM_MAX * 2) +/******************/ +/* xmm6260 specific */ + +#define IOCTL_LINK_CONTROL_ENABLE _IO('o', 0x30) +#define IOCTL_LINK_CONTROL_ACTIVE _IO('o', 0x31) +#define IOCTL_LINK_GET_HOSTWAKE _IO('o', 0x32) +#define IOCTL_LINK_CONNECTED _IO('o', 0x33) +#define IOCTL_LINK_SET_BIAS_CLEAR _IO('o', 0x34) + +/* VID,PID for IMC - XMM6260, XMM6262*/ +#define IMC_BOOT_VID 0x058b +#define IMC_BOOT_PID 0x0041 +#define IMC_MAIN_VID 0x1519 +#define IMC_MAIN_PID 0x0020 +/* VID,PID for STE - M7400 */ +#define STE_BOOT_VID 0x04cc +#define STE_BOOT_PID 0x7400 +#define STE_MAIN_VID 0x04cc +#define STE_MAIN_PID 0x2333 + +enum { + BOOT_DOWN = 0, + IPC_CHANNEL +}; + +enum ch_state { + STATE_SUSPENDED, + STATE_RESUMED, +}; + +#define HOSTWAKE_TRIGLEVEL 0 + +#endif diff --git a/samsung-ipc/device/xmm6260/modem_prj.h b/samsung-ipc/device/xmm6260/modem_prj.h index df4c37d..99f6087 100644 --- a/samsung-ipc/device/xmm6260/modem_prj.h +++ b/samsung-ipc/device/xmm6260/modem_prj.h @@ -13,14 +13,26 @@ * */ +#include +#include +#include + +#define u8 uint8_t +#define u16 uint16_t +#define u32 uint32_t +#define u64 uint64_t + #ifndef __MODEM_PRJ_H__ #define __MODEM_PRJ_H__ -#include +#define MAX_CPINFO_SIZE 512 #define MAX_LINK_DEVTYPE 3 -#define MAX_RAW_DEVS 32 -#define MAX_NUM_IO_DEV (MAX_RAW_DEVS + 4) + +#define MAX_FMT_DEVS 10 +#define MAX_RAW_DEVS 32 +#define MAX_RFS_DEVS 10 +#define MAX_NUM_IO_DEV (MAX_FMT_DEVS + MAX_RAW_DEVS + MAX_RFS_DEVS) #define IOCTL_MODEM_ON _IO('o', 0x19) #define IOCTL_MODEM_OFF _IO('o', 0x20) @@ -33,7 +45,7 @@ #define IOCTL_MODEM_PROTOCOL_RESUME _IO('o', 0x26) #define IOCTL_MODEM_STATUS _IO('o', 0x27) -#define IOCTL_MODEM_GOTA_START _IO('o', 0x28) +#define IOCTL_MODEM_DL_START _IO('o', 0x28) #define IOCTL_MODEM_FW_UPDATE _IO('o', 0x29) #define IOCTL_MODEM_NET_SUSPEND _IO('o', 0x30) @@ -72,10 +84,76 @@ #define PSD_DATA_CHID_BEGIN 0x2A #define PSD_DATA_CHID_END 0x38 +#define PS_DATA_CH_0 10 +#define PS_DATA_CH_LAST 24 + #define IP6VERSION 6 #define SOURCE_MAC_ADDR {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC} +/* Debugging features */ +#define MAX_MIF_LOG_PATH_LEN 128 +#define MAX_MIF_LOG_FILE_SIZE 0x800000 /* 8 MB */ + +#define MAX_MIF_EVT_BUFF_SIZE 256 +#define MAX_MIF_TIME_LEN 32 +#define MAX_MIF_NAME_LEN 16 +#define MAX_MIF_STR_LEN 127 +#define MAX_MIF_LOG_LEN 128 + +enum mif_event_id { + MIF_IRQ_EVT = 0, + MIF_LNK_RX_EVT, + MIF_MUX_RX_EVT, + MIF_IOD_RX_EVT, + MIF_IOD_TX_EVT, + MIF_MUX_TX_EVT, + MIF_LNK_TX_EVT, + MAX_MIF_EVT +}; + +struct dpram_queue_status { + unsigned in; + unsigned out; +}; + +struct dpram_queue_status_pair { + struct dpram_queue_status txq; + struct dpram_queue_status rxq; +}; + +struct dpram_irq_buff { + unsigned magic; + unsigned access; + struct dpram_queue_status_pair qsp[MAX_IPC_DEV]; + unsigned int2ap; + unsigned int2cp; +}; + +struct mif_event_buff { + char time[MAX_MIF_TIME_LEN]; + + struct timeval tv; + enum mif_event_id evt; + + char mc[MAX_MIF_NAME_LEN]; + + char iod[MAX_MIF_NAME_LEN]; + + char ld[MAX_MIF_NAME_LEN]; + enum modem_link link_type; + + unsigned rcvd; + unsigned len; + union { + u8 data[MAX_MIF_LOG_LEN]; + struct dpram_irq_buff dpram_irqb; + }; +}; + +#define MIF_LOG_DIR "/sdcard" +#define MIF_LOG_LV_FILE "/data/.mif_log_level" + /* Does modem ctl structure will use state ? or status defined below ?*/ enum modem_state { STATE_OFFLINE, @@ -85,6 +163,8 @@ enum modem_state { STATE_ONLINE, STATE_NV_REBUILDING, /* <= rebuilding start */ STATE_LOADER_DONE, + STATE_SIM_ATTACH, + STATE_SIM_DETACH, }; enum com_state { @@ -95,6 +175,25 @@ enum com_state { COM_CRASH, }; +enum link_mode { + LINK_MODE_INVALID = 0, + LINK_MODE_IPC, + LINK_MODE_BOOT, + LINK_MODE_DLOAD, + LINK_MODE_ULOAD, +}; + +struct sim_state { + bool online; /* SIM is online? */ + bool changed; /* online is changed? */ +}; + +#define HDLC_START 0x7F +#define HDLC_END 0x7E +#define SIZE_OF_HDLC_START 1 +#define SIZE_OF_HDLC_END 1 +#define MAX_LINK_PADDING_SIZE 3 + struct header_data { char hdr[HDLC_HEADER_MAX_SIZE]; unsigned len; @@ -102,26 +201,30 @@ struct header_data { char start; /*hdlc start header 0x7F*/ }; -struct sipc4_hdlc_fmt_hdr { - uint16_t len; - uint8_t control; +struct fmt_hdr { + u16 len; + u8 control; } __attribute__((packed)); -struct sipc4_fmt_hdr { - uint16_t len; - uint8_t msg_seq; - uint8_t ack_seq; - uint8_t main_cmd; - uint8_t sub_cmd; - uint8_t cmd_type; +struct raw_hdr { + u32 len; + u8 channel; + u8 control; } __attribute__((packed)); -//Link control +struct rfs_hdr { + u32 len; + u8 cmd; + u8 id; +} __attribute__((packed)); -#define IOCTL_LINK_CONTROL_ENABLE _IO('o', 0x30) -#define IOCTL_LINK_CONTROL_ACTIVE _IO('o', 0x31) -#define IOCTL_LINK_GET_HOSTWAKE _IO('o', 0x32) -#define IOCTL_LINK_CONNECTED _IO('o', 0x33) -#define IOCTL_LINK_SET_BIAS_CLEAR _IO('o', 0x34) +struct sipc_fmt_hdr { + u16 len; + u8 msg_seq; + u8 ack_seq; + u8 main_cmd; + u8 sub_cmd; + u8 cmd_type; +} __attribute__((packed)); -#endif //__MODEM_PRJ_H__ +#endif diff --git a/samsung-ipc/device/xmm6260/xmm6260.c b/samsung-ipc/device/xmm6260/xmm6260.c new file mode 100644 index 0000000..a5c0779 --- /dev/null +++ b/samsung-ipc/device/xmm6260/xmm6260.c @@ -0,0 +1,44 @@ +/* + * This file is part of libsamsung-ipc. + * + * Copyright (C) 2013 Paul Kocialkowski + * Copyright (C) 2012 Alexander Tarasikov + * + * 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 + +#include "xmm6260.h" + +unsigned char xmm6260_crc_calculate(void *buffer, int length) +{ + unsigned char crc; + unsigned char *p; + + if (buffer == NULL || length <= 0) + return 0; + + p = (unsigned char *) buffer; + + crc = 0; + while (length--) + crc ^= *p++; + + return crc; +} + +// vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/device/xmm6260/xmm6260.h b/samsung-ipc/device/xmm6260/xmm6260.h new file mode 100644 index 0000000..d56ad1d --- /dev/null +++ b/samsung-ipc/device/xmm6260/xmm6260.h @@ -0,0 +1,46 @@ +/* + * 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 . + * + */ + +#ifndef __XMM6260_H__ +#define __XMM6260_H__ + +#define XMM6260_AT "ATAT" +#define XMM6260_PSI_PADDING 0xFF +#define XMM6260_PSI_MAGIC 0x30 +#define XMM6260_SEC_END_MAGIC 0x0000 +#define XMM6260_HW_RESET_MAGIC 0x111001 +#define XMM6260_DATA_SIZE 0x1000 + +#define XMM6260_COMMAND_SET_PORT_CONFIG 0x86 +#define XMM6260_COMMAND_SEC_START 0x204 +#define XMM6260_COMMAND_SEC_END 0x205 +#define XMM6260_COMMAND_HW_RESET 0x208 +#define XMM6260_COMMAND_FLASH_SET_ADDRESS 0x802 +#define XMM6260_COMMAND_FLASH_WRITE_BLOCK 0x804 + +#define XMM6260_FIRMWARE_ADDRESS 0x60300000 +#define XMM6260_NV_DATA_ADDRESS 0x60E80000 +#define XMM6260_MPS_DATA_ADDRESS 0x61080000 + +unsigned char xmm6260_crc_calculate(void *buffer, int length); + +#endif + +// vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/device/xmm6260/xmm6260_hsic.c b/samsung-ipc/device/xmm6260/xmm6260_hsic.c new file mode 100644 index 0000000..263934b --- /dev/null +++ b/samsung-ipc/device/xmm6260/xmm6260_hsic.c @@ -0,0 +1,610 @@ +/* + * This file is part of libsamsung-ipc. + * + * Copyright (C) 2013 Paul Kocialkowski + * Copyright (C) 2012 Alexander Tarasikov + * + * Based on the incomplete C++ implementation which is: + * Copyright (C) 2012 Sergey Gridasov + * + * 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 +#include +#include +#include + +#include +#include + +#include "xmm6260.h" +#include "xmm6260_hsic.h" + +int xmm6260_hsic_ack_read(int device_fd, unsigned short ack) +{ + struct timeval timeout; + fd_set fds; + + unsigned short value; + int rc; + int i; + + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + FD_ZERO(&fds); + FD_SET(device_fd, &fds); + + for (i = 0; i < 50; i++) { + rc = select(device_fd + 1, &fds, NULL, NULL, &timeout); + if (rc <= 0) + return -1; + + value = 0; + rc = read(device_fd, &value, sizeof(value)); + if (rc < (int) sizeof(value)) + continue; + + if (value == ack) + return 0; + } + + return -1; +} + +int xmm6260_hsic_psi_send(struct ipc_client *client, int device_fd, + void *psi_data, unsigned short psi_size) +{ + struct xmm6260_hsic_psi_header psi_header; + char at[] = XMM6260_AT; + unsigned char psi_ack; + unsigned char chip_id; + unsigned char psi_crc; + + struct timeval timeout; + fd_set fds; + int wc; + + unsigned char *p; + int length; + int rc; + int i; + + if (client == NULL || device_fd < 0 || psi_data == NULL || psi_size == 0) + return -1; + + FD_ZERO(&fds); + + i = 0; + length = strlen(at); + + do { + FD_SET(device_fd, &fds); + + timeout.tv_sec = 0; + timeout.tv_usec = 100000; + + rc = write(device_fd, at, length); + if (rc < length) { + ipc_client_log(client, "Writing ATAT in ASCII failed"); + goto error; + } + ipc_client_log(client, "Wrote ATAT in ASCII"); + + rc = select(device_fd + 1, &fds, NULL, NULL, &timeout); + if (rc < 0) { + ipc_client_log(client, "Waiting for bootup failed"); + goto error; + } + + if (i++ > 50) { + ipc_client_log(client, "Waiting for bootup failed"); + goto error; + } + } while(rc == 0); + + FD_SET(device_fd, &fds); + + timeout.tv_sec = 0; + timeout.tv_usec = 100000; + + rc = select(device_fd + 1, &fds, NULL, NULL, &timeout); + if (rc <= 0) { + ipc_client_log(client, "Reading chip id failed"); + goto error; + } + + psi_ack = 0; + rc = read(device_fd, &psi_ack, sizeof(psi_ack)); + if (rc < 0 || psi_ack != XMM6260_HSIC_BOOT0_ACK) { + ipc_client_log(client, "Reading boot ACK failed"); + goto error; + } + + rc = select(device_fd + 1, &fds, NULL, NULL, &timeout); + if (rc <= 0) { + ipc_client_log(client, "Reading chip id failed"); + goto error; + } + + chip_id = 0; + rc = read(device_fd, &chip_id, sizeof(chip_id)); + if (rc < 0) { + ipc_client_log(client, "Reading chip id failed"); + goto error; + } + ipc_client_log(client, "Read chip id (0x%x)", chip_id); + + psi_header.magic = XMM6260_PSI_MAGIC; + psi_header.length = psi_size; + psi_header.padding = XMM6260_PSI_PADDING; + + rc = write(device_fd, &psi_header, sizeof(psi_header)); + if (rc < (int) sizeof(psi_header)) { + ipc_client_log(client, "Writing PSI header failed"); + goto error; + } + ipc_client_log(client, "Wrote PSI header"); + + p = (unsigned char *) psi_data; + + wc = 0; + while (wc < psi_size) { + rc = write(device_fd, (void *) p, psi_size - wc); + if (rc < 0) { + ipc_client_log(client, "Writing PSI failed"); + goto error; + } + + p += rc; + wc += rc; + } + + psi_crc = xmm6260_crc_calculate(psi_data, psi_size); + + ipc_client_log(client, "Wrote PSI, CRC is 0x%x", psi_crc); + + rc = write(device_fd, &psi_crc, sizeof(psi_crc)); + if (rc < (int) sizeof(psi_crc)) { + ipc_client_log(client, "Writing PSI CRC failed"); + goto error; + } + ipc_client_log(client, "Wrote PSI CRC (0x%x)", psi_crc); + + timeout.tv_sec = 0; + timeout.tv_usec = 100000; + + for (i = 0; i < XMM6260_HSIC_PSI_UNKNOWN_COUNT; i++) { + rc = select(device_fd + 1, &fds, NULL, NULL, &timeout); + if (rc <= 0) { + ipc_client_log(client, "Reading PSI unknown failed"); + goto error; + } + + rc = read(device_fd, &psi_ack, sizeof(psi_ack)); + if (rc < (int) sizeof(psi_ack)) { + ipc_client_log(client, "Reading PSI unknown failed"); + goto error; + } + } + + for (i = 0; i < XMM6260_HSIC_PSI_CRC_ACK_COUNT ; i++) { + rc = select(device_fd + 1, &fds, NULL, NULL, &timeout); + if (rc <= 0) { + ipc_client_log(client, "Reading PSI CRC ACK failed"); + goto error; + } + + rc = read(device_fd, &psi_ack, sizeof(psi_ack)); + if (rc < (int) sizeof(psi_ack) || psi_ack != XMM6260_HSIC_PSI_CRC_ACK) { + ipc_client_log(client, "Reading PSI CRC ACK failed"); + goto error; + } + } + ipc_client_log(client, "Read PSI CRC ACK"); + + rc = xmm6260_hsic_ack_read(device_fd, XMM6260_HSIC_PSI_ACK); + if (rc < 0) { + ipc_client_log(client, "Reading PSI ACK failed"); + goto error; + } + ipc_client_log(client, "Read PSI ACK"); + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + return rc; +} + +int xmm6260_hsic_ebl_send(struct ipc_client *client, int device_fd, + void *ebl_data, int ebl_size) +{ + unsigned char ebl_crc; + + int chunk; + int count; + int wc; + + unsigned char *p; + int length; + int rc; + + if (client == NULL || device_fd < 0 || ebl_data == NULL || ebl_size <= 0) + return -1; + + length = sizeof(ebl_size); + + rc = write(device_fd, &ebl_size, length); + if (rc < length) { + ipc_client_log(client, "Writing EBL size failed"); + goto error; + } + ipc_client_log(client, "Wrote EBL size"); + + rc = xmm6260_hsic_ack_read(device_fd, XMM6260_HSIC_EBL_SIZE_ACK); + if (rc < 0) { + ipc_client_log(client, "Reading EBL size ACK failed"); + goto error; + } + + p = (unsigned char *) ebl_data; + + chunk = XMM6260_HSIC_EBL_CHUNK; + wc = 0; + while (wc < ebl_size) { + count = chunk < ebl_size - wc ? chunk : ebl_size - wc; + + rc = write(device_fd, (void *) p, count); + if (rc < 0) { + ipc_client_log(client, "Writing EBL failed"); + goto error; + } + + p += rc; + wc += rc; + } + + ebl_crc = xmm6260_crc_calculate(ebl_data, ebl_size); + + ipc_client_log(client, "Wrote EBL, CRC is 0x%x", ebl_crc); + + rc = write(device_fd, &ebl_crc, sizeof(ebl_crc)); + if (rc < (int) sizeof(ebl_crc)) { + ipc_client_log(client, "Writing EBL CRC failed"); + goto error; + } + ipc_client_log(client, "Wrote EBL CRC (0x%x)", ebl_crc); + + rc = xmm6260_hsic_ack_read(device_fd, XMM6260_HSIC_EBL_ACK); + if (rc < 0) { + ipc_client_log(client, "Reading EBL ACK failed"); + goto error; + } + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + return rc; +} + +int xmm6260_hsic_command_send(int device_fd, unsigned short code, + void *data, int size, int command_data_size, int ack) +{ + struct xmm6260_hsic_command_header header; + void *buffer = NULL; + int length; + + struct timeval timeout; + fd_set fds; + + unsigned char *p; + int rc; + int i; + + if (device_fd < 0 || data == NULL || size <= 0 || command_data_size < size) + return -1; + + header.checksum = (size & 0xffff) + code; + header.code = code; + header.data_size = size; + + p = (unsigned char *) data; + + for (i = 0; i < size; i++) + header.checksum += *p++; + + length = command_data_size + sizeof(header); + buffer = malloc(length); + + memset(buffer, 0, length); + p = (unsigned char *) buffer; + memcpy(p, &header, sizeof(header)); + p += sizeof(header); + memcpy(p, data, size); + + rc = write(device_fd, buffer, length); + if (rc < length) + goto error; + + if (!ack) { + rc = 0; + goto complete; + } + + memset(buffer, 0, length); + + FD_ZERO(&fds); + FD_SET(device_fd, &fds); + + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + rc = select(device_fd + 1, &fds, NULL, NULL, &timeout); + if (rc <= 0) + goto error; + + rc = read(device_fd, &header, sizeof(header)); + if (rc < (int) sizeof(header)) + goto error; + + rc = select(device_fd + 1, &fds, NULL, NULL, &timeout); + if (rc <= 0) + goto error; + + rc = read(device_fd, buffer, command_data_size); + if (rc < command_data_size) + goto error; + + if (header.code != code) + goto error; + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + if (buffer != NULL) + free(buffer); + + return rc; +} + +int xmm6260_hsic_modem_data_send(int device_fd, void *data, int size, int address) +{ + int chunk; + int count; + int c; + + unsigned char *p; + int rc; + + if (device_fd < 0 || data == NULL || size <= 0) + return -1; + + rc = xmm6260_hsic_command_send(device_fd, XMM6260_COMMAND_FLASH_SET_ADDRESS, &address, sizeof(address), XMM6260_HSIC_FLASH_SET_ADDRESS_SIZE, 1); + if (rc < 0) + goto error; + + p = (unsigned char *) data; + + chunk = XMM6260_HSIC_MODEM_DATA_CHUNK; + c = 0; + while (c < size) { + count = chunk < size - c ? chunk : size - c; + + rc = xmm6260_hsic_command_send(device_fd, XMM6260_COMMAND_FLASH_WRITE_BLOCK, p, count, XMM6260_HSIC_FLASH_WRITE_BLOCK_SIZE, 0); + if (rc < 0) + goto error; + + p += count; + c += count; + } + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + return rc; +} + +int xmm6260_hsic_port_config_send(struct ipc_client *client, int device_fd) +{ + void *buffer = NULL; + int length; + + struct timeval timeout; + fd_set fds; + + int rc; + + if (client == NULL || device_fd < 0) + return -1; + + FD_ZERO(&fds); + FD_SET(device_fd, &fds); + + timeout.tv_sec = 2; + timeout.tv_usec = 0; + + rc = select(device_fd + 1, &fds, NULL, NULL, &timeout); + if (rc <= 0) + goto error; + + length = XMM6260_HSIC_PORT_CONFIG_SIZE; + buffer = malloc(length); + + rc = select(device_fd + 1, &fds, NULL, NULL, &timeout); + if (rc <= 0) + goto error; + + rc = read(device_fd, buffer, length); + if (rc < length) { + ipc_client_log(client, "Reading port config failed"); + goto error; + } + ipc_client_log(client, "Read port config"); + + rc = xmm6260_hsic_command_send(device_fd, XMM6260_COMMAND_SET_PORT_CONFIG, buffer, length, XMM6260_HSIC_SET_PORT_CONFIG_SIZE, 1); + if (rc < 0) { + ipc_client_log(client, "Sending port config command failed"); + goto error; + } + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + if (buffer != NULL) + free(buffer); + + return rc; +} + +int xmm6260_hsic_sec_start_send(struct ipc_client *client, int device_fd, + void *sec_data, int sec_size) +{ + int rc; + + if (client == NULL || device_fd < 0 || sec_data == NULL || sec_size <= 0) + return -1; + + rc = xmm6260_hsic_command_send(device_fd, XMM6260_COMMAND_SEC_START, sec_data, sec_size, XMM6260_HSIC_SEC_START_SIZE, 1); + if (rc < 0) + return -1; + + return 0; +} + +int xmm6260_hsic_sec_end_send(struct ipc_client *client, int device_fd) +{ + unsigned short sec_data; + int sec_size; + int rc; + + if (client == NULL || device_fd < 0) + return -1; + + sec_data = XMM6260_SEC_END_MAGIC; + sec_size = sizeof(sec_data); + + rc = xmm6260_hsic_command_send(device_fd, XMM6260_COMMAND_SEC_END, &sec_data, sec_size, XMM6260_HSIC_SEC_END_SIZE, 1); + if (rc < 0) + return -1; + + return 0; +} + +int xmm6260_hsic_firmware_send(struct ipc_client *client, int device_fd, + void *firmware_data, int firmware_size) +{ + int rc; + + if (client == NULL || device_fd < 0 || firmware_data == NULL || firmware_size <= 0) + return -1; + + rc = xmm6260_hsic_modem_data_send(device_fd, firmware_data, firmware_size, XMM6260_FIRMWARE_ADDRESS); + if (rc < 0) + return -1; + + return 0; +} + +int xmm6260_hsic_nv_data_send(struct ipc_client *client, int device_fd) +{ + void *nv_data = NULL; + int nv_size; + int rc; + + if (client == NULL || device_fd < 0) + return -1; + + rc = nv_data_check(client); + if (rc < 0) { + ipc_client_log(client, "Checking nv_data failed"); + goto error; + } + ipc_client_log(client, "Checked nv_data"); + + rc = nv_data_md5_check(client); + if (rc < 0) { + ipc_client_log(client, "Checking nv_data md5 failed"); + goto error; + } + ipc_client_log(client, "Checked nv_data md5"); + + nv_data = file_data_read(nv_data_path(client), nv_data_size(client), nv_data_chunk_size(client)); + if (nv_data == NULL) { + ipc_client_log(client, "Reading nv_data failed"); + goto error; + } + ipc_client_log(client, "Read nv_data"); + + nv_size = nv_data_size(client); + + rc = xmm6260_hsic_modem_data_send(device_fd, nv_data, nv_size, XMM6260_NV_DATA_ADDRESS); + if (rc < 0) + goto error; + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + if (nv_data != NULL) + free(nv_data); + + return rc; +} + +int xmm6260_hsic_hw_reset_send(struct ipc_client *client, int device_fd) +{ + unsigned int hw_reset_data; + int hw_reset_size; + int rc; + + if (client == NULL || device_fd < 0) + return -1; + + hw_reset_data = XMM6260_HW_RESET_MAGIC; + hw_reset_size = sizeof(hw_reset_data); + + rc = xmm6260_hsic_command_send(device_fd, XMM6260_COMMAND_HW_RESET, &hw_reset_data, hw_reset_size, XMM6260_HSIC_HW_RESET_SIZE, 0); + if (rc < 0) + return -1; + + return 0; +} + +// vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/device/xmm6260/xmm6260_hsic.h b/samsung-ipc/device/xmm6260/xmm6260_hsic.h new file mode 100644 index 0000000..5032e41 --- /dev/null +++ b/samsung-ipc/device/xmm6260/xmm6260_hsic.h @@ -0,0 +1,70 @@ +/* + * This file is part of libsamsung-ipc. + * + * Copyright (C) 2013 Paul Kocialkowski + * Copyright (C) 2012 Alexander Tarasikov + * + * 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 . + * + */ + +#ifndef __XMM6260_HSIC_H__ +#define __XMM6260_HSIC_H__ + +#define XMM6260_HSIC_BOOT0_ACK 0xF0 +#define XMM6260_HSIC_PSI_UNKNOWN_COUNT 22 +#define XMM6260_HSIC_PSI_CRC_ACK 0x01 +#define XMM6260_HSIC_PSI_CRC_ACK_COUNT 2 +#define XMM6260_HSIC_PSI_ACK 0xAA00 +#define XMM6260_HSIC_EBL_SIZE_ACK 0xCCCC +#define XMM6260_HSIC_EBL_ACK 0xA551 +#define XMM6260_HSIC_EBL_CHUNK 0x4000 +#define XMM6260_HSIC_PORT_CONFIG_SIZE 0x4C +#define XMM6260_HSIC_SET_PORT_CONFIG_SIZE 0x800 +#define XMM6260_HSIC_SEC_START_SIZE 0x4000 +#define XMM6260_HSIC_SEC_END_SIZE 0x4000 +#define XMM6260_HSIC_HW_RESET_SIZE 0x4000 +#define XMM6260_HSIC_FLASH_SET_ADDRESS_SIZE 0x4000 +#define XMM6260_HSIC_FLASH_WRITE_BLOCK_SIZE 0x4000 +#define XMM6260_HSIC_MODEM_DATA_CHUNK 0x4000 + +struct xmm6260_hsic_psi_header { + unsigned char magic; + unsigned short length; + unsigned char padding; +} __attribute__((packed)); + +struct xmm6260_hsic_command_header { + unsigned short checksum; + unsigned short code; + unsigned int data_size; +} __attribute__((packed)); + +int xmm6260_hsic_psi_send(struct ipc_client *client, int device_fd, + void *psi_data, unsigned short psi_size); +int xmm6260_hsic_ebl_send(struct ipc_client *client, int device_fd, + void *ebl_data, int ebl_size); + +int xmm6260_hsic_port_config_send(struct ipc_client *client, int device_fd); +int xmm6260_hsic_sec_start_send(struct ipc_client *client, int device_fd, + void *sec_data, int sec_size); +int xmm6260_hsic_sec_end_send(struct ipc_client *client, int device_fd); +int xmm6260_hsic_firmware_send(struct ipc_client *client, int device_fd, + void *firmware_data, int firmware_size); +int xmm6260_hsic_nv_data_send(struct ipc_client *client, int device_fd); +int xmm6260_hsic_hw_reset_send(struct ipc_client *client, int device_fd); + +#endif + +// vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/device/xmm6260/xmm6260_ipc.c b/samsung-ipc/device/xmm6260/xmm6260_ipc.c deleted file mode 100644 index b8c1f60..0000000 --- a/samsung-ipc/device/xmm6260/xmm6260_ipc.c +++ /dev/null @@ -1,399 +0,0 @@ -/** - * This file is part of libsamsung-ipc. - * - * Copyright (C) 2012 Alexander Tarasikov - * Copyright (C) 2011 Paul Kocialkowski - * based on crespo IPC code which is: - * - * Copyright (C) 2011 Paul Kocialkowski - * Joerie de Gram - * Simon Busch - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "ipc.h" - -#include "xmm6260_ipc.h" -#include "xmm6260_loader.h" -#include "xmm6260_modemctl.h" -#include "modem_prj.h" - -int xmm6260_ipc_fmt_send(struct ipc_client *client, struct ipc_message_info *request) -{ - struct ipc_header *hdr; - unsigned char *frame; - unsigned char *payload; - size_t frame_length; - - /* Frame IPC header + payload length */ - frame_length = (sizeof(*hdr) + request->length); - - frame = (unsigned char*)malloc(frame_length); - hdr = (struct ipc_header*)frame; - - /* IPC header */ - hdr->length = frame_length; - hdr->mseq = request->mseq; - hdr->aseq = request->aseq; - hdr->group = request->group; - hdr->index = request->index; - hdr->type = request->type; - - /* IPC payload */ - payload = (frame + sizeof(*hdr)); - memcpy(payload, request->data, request->length); - - ipc_client_log_send(client, request, __func__); - - client->handlers->write(client->handlers->transport_data, frame, frame_length); - - free(frame); - - return 0; -} - -int xmm6260_ipc_fmt_recv(struct ipc_client *client, struct ipc_message_info *response) -{ - unsigned char buf[IPC_MAX_XFER] = {}; - unsigned char *data; - unsigned short *frame_length; - - struct ipc_header ipc = { - .length = 0, - }; - - int num_read = 0; - int left = 0; - - if (!client || !response) - return -1; - - num_read = client->handlers->read(client->handlers->transport_data, buf, IPC_MAX_XFER); - - if (num_read <= 0) { - ipc_client_log(client, "read failed to read ipc length: %d", num_read); - response->data = 0; - response->length = 0; - goto done; - } - - memcpy(&ipc, buf, sizeof(ipc)); - left = ipc.length - num_read; - - if (left > 0) - num_read = client->handlers->read(client->handlers->transport_data, buf + num_read, left); - - memcpy(&ipc, buf, sizeof(ipc)); - - response->mseq = ipc.mseq; - response->aseq = ipc.aseq; - response->group = ipc.group; - response->index = ipc.index; - response->type = ipc.type; - response->cmd = IPC_COMMAND(response); - response->length = ipc.length - sizeof(ipc); - response->data = NULL; - - if (response->length > 0) { - response->data = (unsigned char*)malloc(response->length); - memcpy(response->data, buf + sizeof(ipc), response->length); - } - - ipc_client_log_recv(client, response, __func__); - -done: - return 0; -} - -int xmm6260_ipc_rfs_recv(struct ipc_client *client, struct ipc_message_info *response) -{ - unsigned char buf[IPC_MAX_XFER] = {}; - struct rfs_hdr header; - int header_recv = 0; - unsigned count=0; - int rc; - int ret = 0; - - do { - rc = client->handlers->read(client->handlers->transport_data, buf, IPC_MAX_XFER); - - if (rc < 0) { - ipc_client_log(client, "Failed to read RFS data."); - ret = -1; - goto done; - } - - // We didn't recieve the header yet - if (!header_recv) { - if ((unsigned) rc < sizeof(struct rfs_hdr)) { - ipc_client_log(client, "Failed to read RFS data."); - ret = -1; - goto done; - } - - memcpy((void *) &header, (void *) buf, sizeof(struct rfs_hdr)); - - if (header.size < sizeof(struct rfs_hdr)) { - ipc_client_log(client, "Invalid size in header"); - ret = -1; - goto done; - } - - response->mseq = 0; - response->aseq = header.id; - response->group = IPC_GROUP_RFS; - response->index = header.cmd; - response->type = 0; - response->length = header.size - sizeof(struct rfs_hdr); - response->data = NULL; - - if (response->length > 0) { - response->data = malloc(response->length); - memcpy(response->data, - (void *) (buf + sizeof(struct rfs_hdr)), - rc - sizeof(struct rfs_hdr)); - } - - header_recv = 1; - } else { - // Still reading data, with no header - memcpy((void *) (response->data + count - sizeof(struct rfs_hdr)), buf, rc); - } - - count += rc; - } while (count < header.size); - - ipc_client_log_recv(client, response, __func__); - -done: - return ret; -} - -int xmm6260_ipc_rfs_send(struct ipc_client *client, struct ipc_message_info *request) -{ - struct rfs_hdr *header = NULL; - char *data = NULL; - int data_length; - int rc; - - data_length = sizeof(struct rfs_hdr) + request->length; - data = malloc(data_length); - memset(data, 0, data_length); - - header = (struct rfs_hdr *) data; - header->id = request->mseq; - header->cmd = request->index; - header->size = data_length; - - memcpy((void *) (data + sizeof(struct rfs_hdr)), request->data, request->length); - - ipc_client_log_send(client, request, __func__); - - rc = client->handlers->write(client->handlers->transport_data, data, data_length); - - return rc; -} - -int xmm6260_ipc_open(void *transport_data, int type) -{ - struct xmm6260_ipc_transport_data *data; - int fd; - - if (transport_data == NULL) - return -1; - - data = (struct xmm6260_ipc_transport_data *) transport_data; - - switch(type) - { - case IPC_CLIENT_TYPE_FMT: - fd = open("/dev/umts_ipc0", O_RDWR | O_NOCTTY | O_NONBLOCK); - break; - case IPC_CLIENT_TYPE_RFS: - fd = open("/dev/umts_rfs0", O_RDWR | O_NOCTTY | O_NONBLOCK); - break; - default: - break; - } - - if(fd < 0) - return -1; - - data->fd = fd; - - return 0; -} - -int xmm6260_ipc_close(void *transport_data) -{ - struct xmm6260_ipc_transport_data *data; - int fd; - - if (transport_data == NULL) - return -1; - - data = (struct xmm6260_ipc_transport_data *) transport_data; - - fd = data->fd; - if (fd < 0) - return -1; - - close(fd); - - return 0; -} - -int xmm6260_ipc_read(void *transport_data, void *buffer, unsigned int length) -{ - struct xmm6260_ipc_transport_data *data; - int fd; - int rc; - - if (transport_data == NULL) - return -1; - - data = (struct xmm6260_ipc_transport_data *) transport_data; - - fd = data->fd; - if(fd < 0) - return -1; - - rc = expect(fd, 100); - if (rc < 0) - return -1; - - rc = read(fd, buffer, length); - if(rc < 0) - return -1; - - return rc; -} - -int xmm6260_ipc_write(void *transport_data, void *buffer, unsigned int length) -{ - struct xmm6260_ipc_transport_data *data; - int fd; - int rc; - - if (transport_data == NULL) - return -1; - - data = (struct xmm6260_ipc_transport_data *) transport_data; - - fd = data->fd; - if(fd < 0) - return -1; - - rc = write(fd, buffer, length); - if(rc < 0) - return -1; - - return rc; -} - -int xmm6260_ipc_poll(void *transport_data, struct timeval *timeout) -{ - struct xmm6260_ipc_transport_data *data; - fd_set fds; - int fd; - int rc; - - if (transport_data == NULL) - return -1; - - data = (struct xmm6260_ipc_transport_data *) transport_data; - - fd = data->fd; - if (fd < 0) - return -1; - - FD_ZERO(&fds); - FD_SET(fd, &fds); - - rc = select(FD_SETSIZE, &fds, NULL, NULL, timeout); - return rc; -} - -int xmm6260_ipc_power_on(void *power_data) -{ - return 0; -} - -int xmm6260_ipc_power_off(void *power_data) -{ - return 0; -} - -int xmm6260_ipc_data_create(void **transport_data, void **power_data, void **gprs_data) -{ - if (transport_data == NULL) - return -1; - - *transport_data = (void *) malloc(sizeof(struct xmm6260_ipc_transport_data)); - memset(*transport_data, 0, sizeof(struct xmm6260_ipc_transport_data)); - - return 0; -} - -int xmm6260_ipc_data_destroy(void *transport_data, void *power_data, void *gprs_data) -{ - if (transport_data == NULL) - return -1; - - free(transport_data); - - return 0; -} - -char *xmm6260_ipc_gprs_get_iface(int cid) -{ - char *iface = NULL; - - if(cid > GPRS_IFACE_COUNT) - return NULL; - - asprintf(&iface, "%s%d", GPRS_IFACE_PREFIX, cid - 1); - - return iface; -} - -int xmm6260_ipc_gprs_get_capabilities(struct ipc_client_gprs_capabilities *capabilities) -{ - if (capabilities == NULL) - return -1; - - capabilities->port_list = 1; - capabilities->cid_max = GPRS_IFACE_COUNT; - - return 0; -} - -// vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/device/xmm6260/xmm6260_ipc.h b/samsung-ipc/device/xmm6260/xmm6260_ipc.h deleted file mode 100644 index 632c300..0000000 --- a/samsung-ipc/device/xmm6260/xmm6260_ipc.h +++ /dev/null @@ -1,63 +0,0 @@ -/** - * This file is part of libsamsung-ipc. - * - * Copyright (C) 2012 Alexander Tarasikov - * Copyright (C) 2011 Paul Kocialkowski - * based on crespo IPC code which is: - * - * Copyright (C) 2011 Paul Kocialkowski - * Joerie de Gram - * Simon Busch - * - * 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 - -#ifndef __XMM6260_IPC_H__ -#define __XMM6260_IPC_H__ - -#define IPC_MAX_XFER 4096 -#define GPRS_IFACE_PREFIX "rmnet" -#define GPRS_IFACE_COUNT 3 - -struct rfs_hdr { - uint32_t size; - uint8_t cmd; - uint8_t id; -} __attribute__ ((packed)); - -int xmm6260_ipc_fmt_send(struct ipc_client *client, struct ipc_message_info *request); -int xmm6260_ipc_fmt_recv(struct ipc_client *client, struct ipc_message_info *response); -int xmm6260_ipc_rfs_recv(struct ipc_client *client, struct ipc_message_info *response); -int xmm6260_ipc_rfs_send(struct ipc_client *client, struct ipc_message_info *request); -int xmm6260_ipc_open(void *transport_data, int type); -int xmm6260_ipc_close(void *transport_data); -int xmm6260_ipc_read(void *transport_data, void *buffer, unsigned int length); -int xmm6260_ipc_write(void *transport_data, void *buffer, unsigned int length); -int xmm6260_ipc_poll(void *transport_data, struct timeval *timeout); -int xmm6260_ipc_power_on(void *power_data); -int xmm6260_ipc_power_off(void *power_data); -int xmm6260_ipc_data_create(void **transport_data, void **power_data, void **gprs_data); -int xmm6260_ipc_data_destroy(void *transport_data, void *power_data, void *gprs_data); -char* xmm6260_ipc_gprs_get_iface(int cid); -int xmm6260_ipc_gprs_get_capabilities(struct ipc_client_gprs_capabilities *capabilities); - -struct xmm6260_ipc_transport_data { - int fd; -}; - -#endif - -// vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/device/xmm6260/xmm6260_loader.c b/samsung-ipc/device/xmm6260/xmm6260_loader.c deleted file mode 100644 index 0c077c6..0000000 --- a/samsung-ipc/device/xmm6260/xmm6260_loader.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * XMM6260 Firmware loader functions - * 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 -#include - -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include "ipc.h" - -#include "xmm6260_loader.h" -#include "xmm6260_modemctl.h" -#include "modem_prj.h" - -unsigned char xmm6260_crc_calculate(void* data, size_t offset, size_t length) -{ - unsigned char crc = 0; - unsigned char *ptr = (unsigned char*) (data + offset); - - while (length--) - crc ^= *ptr++; - - return crc; -} - -int expect(int fd, unsigned timeout) -{ - int ret = 0; - - struct timeval tv = { - tv.tv_sec = timeout / 1000, - tv.tv_usec = 1000 * (timeout % 1000), - }; - - fd_set read_set; - FD_ZERO(&read_set); - FD_SET(fd, &read_set); - - ret = select(fd + 1, &read_set, 0, 0, &tv); - - if (ret < 0) - goto fail; - - if (ret < 1 || !FD_ISSET(fd, &read_set)) - goto fail; - -fail: - return ret; -} - -int expect_read(int fd, void *buf, size_t size) -{ - int ret; - - if ((ret = expect(fd, DEFAULT_TIMEOUT)) < 1) - return ret; - - return read(fd, buf, size); -} - -int expect_data(int fd, void *data, size_t size) -{ - int ret; - char buf[size]; - - if ((ret = expect_read(fd, buf, size)) != size) { - ret = -1; - return ret; - } - - ret = memcmp(buf, data, size); - - return ret; -} diff --git a/samsung-ipc/device/xmm6260/xmm6260_loader.h b/samsung-ipc/device/xmm6260/xmm6260_loader.h deleted file mode 100644 index 9f19068..0000000 --- a/samsung-ipc/device/xmm6260/xmm6260_loader.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * XMM6260 Firmware loader functions - * 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 . - */ - -#ifndef __XMM6260_LOADER_H__ -#define __XMM6260_LOADER_H__ - -#define RADIO_MAP_SIZE (16 << 20) -#define DEFAULT_TIMEOUT 50 - -/* - * Offset and length to describe a part of XMM6260 firmware - */ -struct xmm6260_radio_part { - size_t offset; - size_t length; -}; - -/* - * Components of the Samsung XMM6260 firmware - */ -enum xmm6260_image { - PSI, - EBL, - SECURE_IMAGE, - FIRMWARE, - NVDATA, -}; - -/* - * Bootloader control interface definitions - */ -enum xmm6260_boot_cmd { - SetPortConf, - - ReqSecStart, - ReqSecEnd, - ReqForceHwReset, - - ReqFlashSetAddress, - ReqFlashWriteBlock, -}; - -/* - * @brief Calculate the checksum for the XMM6260 bootloader protocol - * - * @param data [in] the data to calculate the checksum for - * @param offset [in] number of bytes to skip - * @param length [in] length of data in bytes - * @return checksum value - */ -unsigned char xmm6260_crc_calculate(void* data, size_t offset, size_t length); - -/* - * @brief Waits for fd to become available for reading - * - * @param fd [in] File descriptor of the socket - * @param timeout [in] Timeout in milliseconds - * @return Negative value indicating error code - * @return Available socket number - 1, as select() - */ -int expect(int fd, unsigned timeout); - -/* - * @brief Waits for data available and reads it to the buffer - * - * @param fd [in] File descriptor of the socket - * @param buf Buffer to hold data - * @param size [in] The number of bytes to read - * @return Negative value indicating error code - * @return The size of data received - */ -int expect_read(int fd, void *buf, size_t size); - -/* - * @brief Receives data and compares with the pattern in memory - * - * @param fd [in] File descriptor of the socket - * @param data [in] The pattern to compare to - * @param size [in] The length of data to read in bytes - * @return Negative value indicating error code - * @return Available socket number - 1, as select() - */ -int expect_data(int fd, void *data, size_t size); - -#endif diff --git a/samsung-ipc/device/xmm6260/xmm6260_mipi.c b/samsung-ipc/device/xmm6260/xmm6260_mipi.c new file mode 100644 index 0000000..902b7b9 --- /dev/null +++ b/samsung-ipc/device/xmm6260/xmm6260_mipi.c @@ -0,0 +1,675 @@ +/* + * This file is part of libsamsung-ipc. + * + * Copyright (C) 2013 Paul Kocialkowski + * Copyright (C) 2012 Alexander Tarasikov + * + * Based on the incomplete C++ implementation which is: + * Copyright (C) 2012 Sergey Gridasov + * + * 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 +#include +#include +#include + +#include +#include + +#include "xmm6260.h" +#include "xmm6260_mipi.h" + +int xmm6260_mipi_crc_calculate(void *buffer, int length) +{ + unsigned char crc; + int mipi_crc; + + crc = xmm6260_crc_calculate(buffer, length); + mipi_crc = (crc << 24) | 0xffffff; + + return mipi_crc; +} + +int xmm6260_mipi_ack_read(int device_fd, unsigned short ack) +{ + struct timeval timeout; + fd_set fds; + + unsigned int value; + int rc; + int i; + + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + FD_ZERO(&fds); + FD_SET(device_fd, &fds); + + for (i = 0; i < 50; i++) { + rc = select(device_fd + 1, &fds, NULL, NULL, &timeout); + if (rc <= 0) + return -1; + + value = 0; + rc = read(device_fd, &value, sizeof(value)); + if (rc < (int) sizeof(value)) + continue; + + if ((value & 0xffff) == ack) + return 0; + } + + return -1; +} + +int xmm6260_mipi_psi_send(struct ipc_client *client, int device_fd, + void *psi_data, unsigned short psi_size) +{ + struct xmm6260_mipi_psi_header psi_header; + char at[] = XMM6260_AT; + int psi_crc; + + struct timeval timeout; + fd_set fds; + int wc; + + unsigned char *p; + int length; + int rc; + int i; + + if (client == NULL || device_fd < 0 || psi_data == NULL || psi_size == 0) + return -1; + + FD_ZERO(&fds); + + i = 0; + length = strlen(at); + + do { + FD_SET(device_fd, &fds); + + timeout.tv_sec = 0; + timeout.tv_usec = 100000; + + rc = write(device_fd, at, length); + if (rc < length) { + ipc_client_log(client, "Writing ATAT in ASCII failed"); + goto error; + } + ipc_client_log(client, "Wrote ATAT in ASCII"); + + rc = select(device_fd + 1, &fds, NULL, NULL, &timeout); + if (rc < 0) { + ipc_client_log(client, "Waiting for bootup failed"); + goto error; + } + + if (i++ > 50) { + ipc_client_log(client, "Waiting for bootup failed"); + goto error; + } + } while(rc == 0); + + rc = xmm6260_mipi_ack_read(device_fd, XMM6260_MIPI_BOOT0_ACK); + if (rc < 0) { + ipc_client_log(client, "Reading boot ACK failed"); + goto error; + } + + psi_header.padding = XMM6260_PSI_PADDING; + psi_header.length = ((psi_size >> 8) & 0xff) | ((psi_size & 0xff) << 8); + psi_header.magic = XMM6260_PSI_MAGIC; + + rc = write(device_fd, &psi_header, sizeof(psi_header)); + if (rc < (int) sizeof(psi_header)) { + ipc_client_log(client, "Writing PSI header failed"); + goto error; + } + ipc_client_log(client, "Wrote PSI header"); + + p = (unsigned char *) psi_data; + + wc = 0; + while (wc < psi_size) { + rc = write(device_fd, (void *) p, psi_size - wc); + if (rc < 0) { + ipc_client_log(client, "Writing PSI failed"); + goto error; + } + + p += rc; + wc += rc; + } + + psi_crc = xmm6260_mipi_crc_calculate(psi_data, psi_size); + + ipc_client_log(client, "Wrote PSI, CRC is 0x%x", psi_crc); + + rc = write(device_fd, &psi_crc, sizeof(psi_crc)); + if (rc < (int) sizeof(psi_crc)) { + ipc_client_log(client, "Writing PSI CRC failed"); + goto error; + } + ipc_client_log(client, "Wrote PSI CRC (0x%x)", psi_crc); + + rc = xmm6260_mipi_ack_read(device_fd, XMM6260_MIPI_PSI_ACK); + if (rc < 0) { + ipc_client_log(client, "Reading PSI ACK failed"); + goto error; + } + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + return rc; +} + +int xmm6260_mipi_ebl_send(struct ipc_client *client, int device_fd, + void *ebl_data, int ebl_size) +{ + unsigned short boot_magic[4]; + unsigned char ebl_crc; + + int chunk; + int count; + int wc; + + unsigned char *p; + int length; + int rc; + + if (client == NULL || device_fd < 0 || ebl_data == NULL || ebl_size <= 0) + return -1; + + boot_magic[0] = 0; + boot_magic[1] = 0; + boot_magic[2] = XMM6260_MIPI_BOOT1_MAGIC; + boot_magic[3] = XMM6260_MIPI_BOOT1_MAGIC; + + length = sizeof(boot_magic); + + rc = write(device_fd, &length, sizeof(length)); + if (rc < (int) sizeof(length)) { + ipc_client_log(client, "Writing boot magic length failed"); + goto error; + } + + rc = write(device_fd, &boot_magic, length); + if (rc < length) { + ipc_client_log(client, "Writing boot magic failed"); + goto error; + } + ipc_client_log(client, "Wrote boot magic"); + + rc = xmm6260_mipi_ack_read(device_fd, XMM6260_MIPI_BOOT1_ACK); + if (rc < 0) { + ipc_client_log(client, "Reading boot magic ACK failed"); + goto error; + } + + length = sizeof(ebl_size); + + rc = write(device_fd, &length, sizeof(length)); + if (rc < (int) sizeof(length)) { + ipc_client_log(client, "Writing EBL size length failed"); + goto error; + } + + rc = write(device_fd, &ebl_size, length); + if (rc < length) { + ipc_client_log(client, "Writing EBL size failed"); + goto error; + } + ipc_client_log(client, "Wrote EBL size"); + + rc = xmm6260_mipi_ack_read(device_fd, XMM6260_MIPI_EBL_SIZE_ACK); + if (rc < 0) { + ipc_client_log(client, "Reading EBL size ACK failed"); + goto error; + } + + ebl_size++; + + rc = write(device_fd, &ebl_size, length); + if (rc < length) { + ipc_client_log(client, "Writing EBL size failed"); + goto error; + } + + ebl_size--; + + p = (unsigned char *) ebl_data; + + chunk = XMM6260_MIPI_EBL_CHUNK; + wc = 0; + while (wc < ebl_size) { + count = chunk < ebl_size - wc ? chunk : ebl_size - wc; + + rc = write(device_fd, (void *) p, count); + if (rc < 0) { + ipc_client_log(client, "Writing EBL failed"); + goto error; + } + + p += rc; + wc += rc; + } + + ebl_crc = xmm6260_crc_calculate(ebl_data, ebl_size); + + ipc_client_log(client, "Wrote EBL, CRC is 0x%x", ebl_crc); + + rc = write(device_fd, &ebl_crc, sizeof(ebl_crc)); + if (rc < (int) sizeof(ebl_crc)) { + ipc_client_log(client, "Writing EBL CRC failed"); + goto error; + } + ipc_client_log(client, "Wrote EBL CRC (0x%x)", ebl_crc); + + rc = xmm6260_mipi_ack_read(device_fd, XMM6260_MIPI_EBL_ACK); + if (rc < 0) { + ipc_client_log(client, "Reading EBL ACK failed"); + goto error; + } + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + return rc; +} + +int xmm6260_mipi_command_send(int device_fd, unsigned short code, + void *data, int size, int ack, int short_tail) +{ + struct xmm6260_mipi_command_header header; + struct xmm6260_mipi_command_tail tail; + int tail_size; + void *buffer = NULL; + int length; + + struct timeval timeout; + fd_set fds; + int chunk; + int c; + + unsigned char *p; + int rc; + int i; + + if (device_fd < 0 || data == NULL || size <= 0) + return -1; + + header.size = size + sizeof(header); + header.magic = XMM6260_MIPI_COMMAND_HEADER_MAGIC; + header.code = code; + header.data_size = size; + + tail.checksum = (size & 0xffff) + code; + tail.magic = XMM6260_MIPI_COMMAND_TAIL_MAGIC; + tail.unknown = XMM6260_MIPI_COMMAND_TAIL_UNKNOWN; + + p = (unsigned char *) data; + + for (i = 0; i < size; i++) + tail.checksum += *p++; + + tail_size = sizeof(tail); + if (short_tail) + tail_size -= sizeof(short); + + length = sizeof(header) + size + tail_size; + buffer = malloc(length); + + p = (unsigned char *) buffer; + memcpy(p, &header, sizeof(header)); + p += sizeof(header); + memcpy(p, data, size); + p += size; + memcpy(p, &tail, tail_size); + + rc = write(device_fd, buffer, length); + if (rc < length) + goto error; + + free(buffer); + buffer = NULL; + + if (!ack) { + rc = 0; + goto complete; + } + + FD_ZERO(&fds); + FD_SET(device_fd, &fds); + + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + rc = select(device_fd + 1, &fds, NULL, NULL, &timeout); + if (rc <= 0) + goto error; + + rc = read(device_fd, &length, sizeof(length)); + if (rc < (int) sizeof(length) || length <= 0) + goto error; + + length += sizeof(unsigned int); + if (length % 4 != 0) + length += length % 4; + + if (length < (int) sizeof(buffer)) + goto error; + + buffer = malloc(length); + + p = (unsigned char *) buffer; + memcpy(p, &length, sizeof(length)); + p += sizeof(length); + + chunk = 4; + c = sizeof(length); + while (c < length) { + rc = select(device_fd + 1, &fds, NULL, NULL, &timeout); + if (rc <= 0) + goto error; + + rc = read(device_fd, (void *) p, chunk); + if (rc < chunk) + goto error; + + p += rc; + c += rc; + } + + memcpy(&header, buffer, sizeof(header)); + if (header.code != code) + goto error; + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + if (buffer != NULL) + free(buffer); + + return rc; +} + +int xmm6260_mipi_modem_data_send(int device_fd, void *data, int size, int address) +{ + int chunk; + int count; + int c; + + unsigned char *p; + int rc; + + if (device_fd < 0 || data == NULL || size <= 0) + return -1; + + rc = xmm6260_mipi_command_send(device_fd, XMM6260_COMMAND_FLASH_SET_ADDRESS, &address, sizeof(address), 1, 0); + if (rc < 0) + goto error; + + p = (unsigned char *) data; + + chunk = XMM6260_MIPI_MODEM_DATA_CHUNK; + c = 0; + while (c < size) { + count = chunk < size - c ? chunk : size - c; + + rc = xmm6260_mipi_command_send(device_fd, XMM6260_COMMAND_FLASH_WRITE_BLOCK, p, count, 1, 1); + if (rc < 0) + goto error; + + p += count; + c += count; + } + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + return rc; +} + +int xmm6260_mipi_port_config_send(struct ipc_client *client, int device_fd) +{ + void *buffer = NULL; + int length; + + struct timeval timeout; + fd_set fds; + int chunk; + int count; + int c; + + unsigned char *p; + int rc; + + if (client == NULL || device_fd < 0) + return -1; + + FD_ZERO(&fds); + FD_SET(device_fd, &fds); + + timeout.tv_sec = 2; + timeout.tv_usec = 0; + + rc = select(device_fd + 1, &fds, NULL, NULL, &timeout); + if (rc <= 0) + goto error; + + rc = read(device_fd, &length, sizeof(length)); + if (rc < (int) sizeof(length) || length <= 0) { + ipc_client_log(client, "Reading port config length failed"); + goto error; + } + ipc_client_log(client, "Read port config length (0x%x)", length); + + buffer = malloc(length); + + p = (unsigned char *) buffer; + + chunk = 4; + c = 0; + while (c < length) { + count = chunk < length - c ? chunk : length - c; + + rc = select(device_fd + 1, &fds, NULL, NULL, &timeout); + if (rc <= 0) + goto error; + + rc = read(device_fd, p, count); + if (rc < count) { + ipc_client_log(client, "Reading port config failed"); + goto error; + } + + p += count; + c += count; + } + ipc_client_log(client, "Read port config"); + + rc = xmm6260_mipi_command_send(device_fd, XMM6260_COMMAND_SET_PORT_CONFIG, buffer, length, 1, 0); + if (rc < 0) { + ipc_client_log(client, "Sending port config command failed"); + goto error; + } + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + if (buffer != NULL) + free(buffer); + + return rc; +} + +int xmm6260_mipi_sec_start_send(struct ipc_client *client, int device_fd, + void *sec_data, int sec_size) +{ + int rc; + + if (client == NULL || device_fd < 0 || sec_data == NULL || sec_size <= 0) + return -1; + + rc = xmm6260_mipi_command_send(device_fd, XMM6260_COMMAND_SEC_START, sec_data, sec_size, 1, 0); + if (rc < 0) + return -1; + + return 0; +} + +int xmm6260_mipi_sec_end_send(struct ipc_client *client, int device_fd) +{ + unsigned short sec_data; + int sec_size; + int rc; + + if (client == NULL || device_fd < 0) + return -1; + + sec_data = XMM6260_SEC_END_MAGIC; + sec_size = sizeof(sec_data); + + rc = xmm6260_mipi_command_send(device_fd, XMM6260_COMMAND_SEC_END, &sec_data, sec_size, 1, 1); + if (rc < 0) + return -1; + + return 0; +} + +int xmm6260_mipi_firmware_send(struct ipc_client *client, int device_fd, + void *firmware_data, int firmware_size) +{ + int rc; + + if (client == NULL || device_fd < 0 || firmware_data == NULL || firmware_size <= 0) + return -1; + + rc = xmm6260_mipi_modem_data_send(device_fd, firmware_data, firmware_size, XMM6260_FIRMWARE_ADDRESS); + if (rc < 0) + return -1; + + return 0; +} + +int xmm6260_mipi_nv_data_send(struct ipc_client *client, int device_fd) +{ + void *nv_data = NULL; + int nv_size; + int rc; + + if (client == NULL || device_fd < 0) + return -1; + + rc = nv_data_check(client); + if (rc < 0) { + ipc_client_log(client, "Checking nv_data failed"); + goto error; + } + ipc_client_log(client, "Checked nv_data"); + + rc = nv_data_md5_check(client); + if (rc < 0) { + ipc_client_log(client, "Checking nv_data md5 failed"); + goto error; + } + ipc_client_log(client, "Checked nv_data md5"); + + nv_data = file_data_read(nv_data_path(client), nv_data_size(client), nv_data_chunk_size(client)); + if (nv_data == NULL) { + ipc_client_log(client, "Reading nv_data failed"); + goto error; + } + ipc_client_log(client, "Read nv_data"); + + nv_size = nv_data_size(client); + + rc = xmm6260_mipi_modem_data_send(device_fd, nv_data, nv_size, XMM6260_NV_DATA_ADDRESS); + if (rc < 0) + goto error; + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + if (nv_data != NULL) + free(nv_data); + + return rc; +} + +int xmm6260_mipi_mps_data_send(struct ipc_client *client, int device_fd, + void *mps_data, int mps_size) +{ + int rc; + + if (client == NULL || device_fd < 0 || mps_data == NULL || mps_size <= 0) + return -1; + + rc = xmm6260_mipi_modem_data_send(device_fd, mps_data, mps_size, XMM6260_MPS_DATA_ADDRESS); + if (rc < 0) + return -1; + + return 0; +} + +int xmm6260_mipi_hw_reset_send(struct ipc_client *client, int device_fd) +{ + unsigned int hw_reset_data; + int hw_reset_size; + int rc; + + if (client == NULL || device_fd < 0) + return -1; + + hw_reset_data = XMM6260_HW_RESET_MAGIC; + hw_reset_size = sizeof(hw_reset_data); + + rc = xmm6260_mipi_command_send(device_fd, XMM6260_COMMAND_HW_RESET, &hw_reset_data, hw_reset_size, 0, 1); + if (rc < 0) + return -1; + + return 0; +} + +// vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/device/xmm6260/xmm6260_mipi.h b/samsung-ipc/device/xmm6260/xmm6260_mipi.h new file mode 100644 index 0000000..c8e7c73 --- /dev/null +++ b/samsung-ipc/device/xmm6260/xmm6260_mipi.h @@ -0,0 +1,74 @@ +/* + * This file is part of libsamsung-ipc. + * + * Copyright (C) 2013 Paul Kocialkowski + * Copyright (C) 2012 Alexander Tarasikov + * + * 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 . + * + */ + +#ifndef __XMM6260_MIPI_H__ +#define __XMM6260_MIPI_H__ + +#define XMM6260_MIPI_BOOT0_ACK 0xFFFF +#define XMM6260_MIPI_BOOT1_MAGIC 0x02 +#define XMM6260_MIPI_BOOT1_ACK 0xAA00 +#define XMM6260_MIPI_PSI_ACK 0xDD01 +#define XMM6260_MIPI_EBL_SIZE_ACK 0xCCCC +#define XMM6260_MIPI_EBL_ACK 0xA551 +#define XMM6260_MIPI_EBL_CHUNK 0xDFC +#define XMM6260_MIPI_MODEM_DATA_CHUNK 0xDF2 +#define XMM6260_MIPI_COMMAND_HEADER_MAGIC 0x02 +#define XMM6260_MIPI_COMMAND_TAIL_MAGIC 0x03 +#define XMM6260_MIPI_COMMAND_TAIL_UNKNOWN 0xEAEA + +struct xmm6260_mipi_psi_header { + unsigned char padding; + unsigned short length; + unsigned char magic; +} __attribute__((packed)); + +struct xmm6260_mipi_command_header { + unsigned int size; + unsigned short magic; + unsigned short code; + unsigned short data_size; +} __attribute__((packed)); + +struct xmm6260_mipi_command_tail { + unsigned short checksum; + unsigned short magic; + unsigned short unknown; +} __attribute__((packed)); + +int xmm6260_mipi_psi_send(struct ipc_client *client, int device_fd, + void *psi_data, unsigned short psi_size); +int xmm6260_mipi_ebl_send(struct ipc_client *client, int device_fd, + void *ebl_data, int ebl_size); + +int xmm6260_mipi_port_config_send(struct ipc_client *client, int device_fd); +int xmm6260_mipi_sec_start_send(struct ipc_client *client, int device_fd, + void *sec_data, int sec_size); +int xmm6260_mipi_sec_end_send(struct ipc_client *client, int device_fd); +int xmm6260_mipi_firmware_send(struct ipc_client *client, int device_fd, + void *firmware_data, int firmware_size); +int xmm6260_mipi_nv_data_send(struct ipc_client *client, int device_fd); +int xmm6260_mipi_mps_data_send(struct ipc_client *client, int device_fd, + void *mps_data, int mps_size); +int xmm6260_mipi_hw_reset_send(struct ipc_client *client, int device_fd); + +#endif + +// vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/device/xmm6260/xmm6260_modemctl.c b/samsung-ipc/device/xmm6260/xmm6260_modemctl.c deleted file mode 100644 index e0048e7..0000000 --- a/samsung-ipc/device/xmm6260/xmm6260_modemctl.c +++ /dev/null @@ -1,181 +0,0 @@ -/* - * XMM6260 Modem Control functions - * 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 -#include - -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include "ipc.h" - -#include "xmm6260_loader.h" -#include "xmm6260_modemctl.h" -#include "modem_prj.h" - -/* - * modemctl generic functions - */ - -int modemctl_link_set_active(struct ipc_client *client, - struct modemctl_io_data *io_data, bool enabled) -{ - unsigned status = enabled; - int ret; - unsigned long ioctl_code; - - ioctl_code = IOCTL_LINK_CONTROL_ACTIVE; - ret = ioctl(io_data->link_fd, ioctl_code, &status); - - if (ret < 0) { - ipc_client_log(client, "failed to set link active to %d", enabled); - goto fail; - } - - return 0; - -fail: - return ret; -} - -int modemctl_link_set_enabled(struct ipc_client *client, - struct modemctl_io_data *io_data, bool enabled) -{ - unsigned status = enabled; - int ret; - unsigned long ioctl_code; - - ioctl_code = IOCTL_LINK_CONTROL_ENABLE; - ret = ioctl(io_data->link_fd, ioctl_code, &status); - - if (ret < 0) { - ipc_client_log(client, "failed to set link state to %d", enabled); - goto fail; - } - - return 0; -fail: - return ret; -} - -int modemctl_wait_link_ready(struct ipc_client *client, - struct modemctl_io_data *io_data) -{ - int ret; - - struct timeval tv_start = {}; - struct timeval tv_end = {}; - - gettimeofday(&tv_start, 0);; - - /* link wakeup timeout in milliseconds */ - long diff = 0; - - do { - ret = ioctl(io_data->link_fd, IOCTL_LINK_CONNECTED, 0); - - if (ret < 0) - goto fail; - - if (ret == 1) - return 0; - - usleep(LINK_POLL_DELAY_US); - gettimeofday(&tv_end, 0);; - - diff = (tv_end.tv_sec - tv_start.tv_sec) * 1000; - diff += (tv_end.tv_usec - tv_start.tv_usec) / 1000; - } while (diff < LINK_TIMEOUT_MS); - - ret = -ETIMEDOUT; - -fail: - return ret; -} - -int modemctl_wait_modem_online(struct ipc_client *client, - struct modemctl_io_data *io_data) -{ - int ret; - - struct timeval tv_start = {}; - struct timeval tv_end = {}; - - gettimeofday(&tv_start, 0);; - - /* link wakeup timeout in milliseconds */ - long diff = 0; - - do { - ret = ioctl(io_data->boot_fd, IOCTL_MODEM_STATUS, 0); - if (ret < 0) - goto fail; - - if (ret == STATE_ONLINE) - return 0; - - usleep(LINK_POLL_DELAY_US); - gettimeofday(&tv_end, 0);; - - diff = (tv_end.tv_sec - tv_start.tv_sec) * 1000; - diff += (tv_end.tv_usec - tv_start.tv_usec) / 1000; - } while (diff < LINK_TIMEOUT_MS); - - ret = -ETIMEDOUT; - -fail: - return ret; -} - -int modemctl_modem_power(struct ipc_client *client, - struct modemctl_io_data *io_data, bool enabled) -{ - if (enabled) - return ioctl(io_data->boot_fd, IOCTL_MODEM_ON, 0); - else - return ioctl(io_data->boot_fd, IOCTL_MODEM_OFF, 0); - - return -1; -} - -int modemctl_modem_boot_power(struct ipc_client *client, - struct modemctl_io_data *io_data, bool enabled) -{ - if (enabled) - return ioctl(io_data->boot_fd, IOCTL_MODEM_BOOT_ON, 0); - else - return ioctl(io_data->boot_fd, IOCTL_MODEM_BOOT_OFF, 0); - - return -1; -} - -// vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/device/xmm6260/xmm6260_modemctl.h b/samsung-ipc/device/xmm6260/xmm6260_modemctl.h deleted file mode 100644 index aab2acb..0000000 --- a/samsung-ipc/device/xmm6260/xmm6260_modemctl.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * XMM6260 Modem Control functions - * 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 . - */ - -#ifndef __XMM6260_MODEMCTL_H__ -#define __XMM6260_MODEMCTL_H__ - -#include - -#define MODEM_DEVICE(x) ("/dev/" #x) -#define LINK_PM MODEM_DEVICE(link_pm) -#define MODEM_DEV MODEM_DEVICE(modem_br) -#define BOOT_DEV MODEM_DEVICE(umts_boot0) -#define IPC_DEV MODEM_DEVICE(umts_ipc0) -#define RFS_DEV MODEM_DEVICE(umts_rfs0) - -#define LINK_POLL_DELAY_US (50 * 1000) -#define LINK_TIMEOUT_MS 2000 - -struct modemctl_io_data { - int link_fd; - int boot_fd; - - int radio_fd; - char *radio_data; - struct stat radio_stat; -}; - -/* - * Function prototypes - */ - -/* - * @brief Activates the modem <-> cpu link data transfer - * - * @param client [in] ipc client - * @param io_data [in] modemctl-specific data - * @param enabled [in] whether to enable or disable link data transport - * @return Negative value indicating error code - * @return ioctl call result - */ -int modemctl_link_set_active(struct ipc_client *client, - struct modemctl_io_data *io_data, bool enabled); - -/* - * @brief Activates the modem <-> cpu link connection - * - * @param client [in] ipc client - * @param io_data [in] modemctl-specific data - * @param enabled [in] the state to set link to - * @return Negative value indicating error code - * @return ioctl call result - */ -int modemctl_link_set_enabled(struct ipc_client *client, - struct modemctl_io_data *io_data, bool enabled); - -/* - * @brief Poll the link until it gets ready or times out - * - * @param client [in] ipc client - * @param io_data [in] modemctl-specific data - * @return Negative value indicating error code - * @return ioctl call result - */ -int modemctl_wait_link_ready(struct ipc_client *client, - struct modemctl_io_data *io_data); - -/* - * @brief Poll the modem until it gets online or times out - * - * @param client [in] ipc client - * @param io_data [in] modemctl-specific data - * @return Negative value indicating error code - * @return ioctl call result - */ -int modemctl_wait_modem_online(struct ipc_client *client, - struct modemctl_io_data *io_data); - -/* - * @brief Sets the modem power - * - * @param client [in] ipc client - * @param io_data [in] modemctl-specific data - * @param enabled [in] whether to enable or disable modem power - * @return Negative value indicating error code - * @return ioctl call result - */ -int modemctl_modem_power(struct ipc_client *client, - struct modemctl_io_data *io_data, bool enabled); - -/* - * @brief Sets the modem bootloader power/UART configuration - * - * @param client [in] ipc client - * @param io_data [in] modemctl-specific data - * @param enabled [in] whether to enable or disable power - * @return Negative value indicating error code - * @return ioctl call result - */ -int modemctl_modem_boot_power(struct ipc_client *client, - struct modemctl_io_data *io_data, bool enabled); - -#endif - -// vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/device/xmm6260/xmm6260_sec_modem.c b/samsung-ipc/device/xmm6260/xmm6260_sec_modem.c new file mode 100644 index 0000000..1a3629d --- /dev/null +++ b/samsung-ipc/device/xmm6260/xmm6260_sec_modem.c @@ -0,0 +1,500 @@ +/* + * This file is part of libsamsung-ipc. + * + * Copyright (C) 2013 Paul Kocialkowski + * Copyright (C) 2012 Alexander Tarasikov + * + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "modem.h" +#include "modem_prj.h" +#include "modem_link_device_hsic.h" + +#include "xmm6260.h" +#include "xmm6260_sec_modem.h" + +int xmm6260_sec_modem_power(int device_fd, int power) +{ + int rc; + + if (device_fd < 0) + return -1; + + rc = ioctl(device_fd, power ? IOCTL_MODEM_ON : IOCTL_MODEM_OFF, 0); + if (rc < 0) + return -1; + + return 0; +} + +int xmm6260_sec_modem_boot_power(int device_fd, int power) +{ + int rc; + + if (device_fd < 0) + return -1; + + rc = ioctl(device_fd, power ? IOCTL_MODEM_BOOT_ON : IOCTL_MODEM_BOOT_OFF, 0); + if (rc < 0) + return -1; + + return 0; +} + +int xmm6260_sec_modem_status_online_wait(int device_fd) +{ + int status; + int i; + + if (device_fd < 0) + return -1; + + i = 0; + for (i = 0; i < 100; i++) { + status = ioctl(device_fd, IOCTL_MODEM_STATUS, 0); + if (status == STATE_ONLINE) + return 0; + + usleep(50000); + } + + return -1; +} + +int xmm6260_sec_modem_hci_power(int power) +{ + int ehci_rc, ohci_rc; + + ehci_rc = sysfs_value_write(XMM6260_SEC_MODEM_EHCI_POWER_SYSFS, !!power); + if (ehci_rc >= 0) + usleep(50000); + + ohci_rc = sysfs_value_write(XMM6260_SEC_MODEM_OHCI_POWER_SYSFS, !!power); + if (ohci_rc >= 0) + usleep(50000); + + if (ehci_rc < 0 && ohci_rc < 0) + return -1; + + return 0; +} + +int xmm6260_sec_modem_link_control_enable(int device_fd, int enable) +{ + int rc; + + if (device_fd < 0) + return -1; + + rc = ioctl(device_fd, IOCTL_LINK_CONTROL_ENABLE, &enable); + if (rc < 0) + return -1; + + return 0; +} + +int xmm6260_sec_modem_link_control_active(int device_fd, int active) +{ + int rc; + + if (device_fd < 0) + return -1; + + rc = ioctl(device_fd, IOCTL_LINK_CONTROL_ACTIVE, &active); + if (rc < 0) + return -1; + + return 0; +} + +int xmm6260_sec_modem_link_connected_wait(int device_fd) +{ + int status; + int i; + + if (device_fd < 0) + return -1; + + i = 0; + for (i = 0; i < 100; i++) { + status = ioctl(device_fd, IOCTL_LINK_CONNECTED, 0); + if (status) + return 0; + + usleep(50000); + } + + return -1; +} + +int xmm6260_sec_modem_link_get_hostwake_wait(int device_fd) +{ + int status; + int i; + + if (device_fd < 0) + return -1; + + i = 0; + for (i = 0; i < 10; i++) { + status = ioctl(device_fd, IOCTL_LINK_GET_HOSTWAKE, 0); + if (status) + return 0; + + usleep(50000); + } + + return -1; +} + +int xmm6260_sec_modem_ipc_fmt_send(struct ipc_client *client, struct ipc_message_info *request) +{ + struct ipc_header header; + void *buffer; + unsigned char *p; + int count; + int rc; + + if (client == NULL || client->handlers == NULL || client->handlers->write == NULL || request == NULL) + return -1; + + ipc_header_fill(&header, request); + + buffer = malloc(header.length); + + memcpy(buffer, &header, sizeof(struct ipc_header)); + if (request->data != NULL && request->length > 0) + memcpy((void *) ((unsigned char *) buffer + sizeof(struct ipc_header)), request->data, request->length); + + ipc_client_log_send(client, request, __func__); + + p = (unsigned char *) buffer; + + count = 0; + while (count < header.length) { + rc = client->handlers->write(client->handlers->transport_data, p, header.length - count); + if (rc <= 0) { + ipc_client_log(client, "Writing FMT data to the modem failed"); + goto error; + } + + count += rc; + p += rc; + } + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + if (buffer != NULL) + free(buffer); + + return rc; +} + +int xmm6260_sec_modem_ipc_fmt_recv(struct ipc_client *client, struct ipc_message_info *response) +{ + struct ipc_header *header; + void *buffer = NULL; + unsigned char *p; + int length; + int count; + int rc; + + if (client == NULL || client->handlers == NULL || client->handlers->read == NULL || response == NULL) + return -1; + + length = XMM6260_DATA_SIZE; + buffer = malloc(length); + + rc = client->handlers->read(client->handlers->transport_data, buffer, length); + if (rc < (int) sizeof(struct ipc_header)) { + ipc_client_log(client, "Reading FMT header from the modem failed"); + goto error; + } + + header = (struct ipc_header *) buffer; + + ipc_message_info_fill(header, response); + + if (header->length > sizeof(struct ipc_header)) { + response->length = header->length - sizeof(struct ipc_header); + response->data = malloc(response->length); + + p = (unsigned char *) response->data; + + count = rc - sizeof(struct ipc_header); + if (count > 0) { + memcpy(p, (void *) ((unsigned char *) buffer + sizeof(struct ipc_header)), count); + p += count; + } + + while (count < (int) response->length) { + rc = client->handlers->read(client->handlers->transport_data, p, response->length - count); + if (rc <= 0) { + ipc_client_log(client, "Reading FMT data from the modem failed"); + goto error; + } + + count += rc; + p += rc; + } + } + + ipc_client_log_recv(client, response, __func__); + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + if (buffer != NULL) + free(buffer); + + return rc; +} + +int xmm6260_sec_modem_ipc_rfs_send(struct ipc_client *client, struct ipc_message_info *request) +{ + struct rfs_hdr header; + void *buffer; + unsigned char *p; + int count; + int rc; + + + if (client == NULL || client->handlers == NULL || client->handlers->write == NULL || request == NULL) + return -1; + + header.id = request->mseq; + header.cmd = request->index; + header.len = sizeof(struct rfs_hdr) + request->length; + + buffer = malloc(header.len); + + memcpy(buffer, &header, sizeof(struct rfs_hdr)); + if (request->data != NULL && request->length > 0) + memcpy((void *) ((unsigned char *) buffer + sizeof(struct rfs_hdr)), request->data, request->length); + + ipc_client_log_send(client, request, __func__); + + p = (unsigned char *) buffer; + + count = 0; + while (count < (int) header.len) { + rc = client->handlers->write(client->handlers->transport_data, p, header.len - count); + if (rc <= 0) { + ipc_client_log(client, "Writing RFS data to the modem failed"); + goto error; + } + + count += rc; + p += rc; + } + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + if (buffer != NULL) + free(buffer); + + return rc; +} + +int xmm6260_sec_modem_ipc_rfs_recv(struct ipc_client *client, struct ipc_message_info *response) +{ + struct rfs_hdr *header; + void *buffer = NULL; + unsigned char *p; + int length; + int count; + int rc; + + if (client == NULL || client->handlers == NULL || client->handlers->read == NULL || response == NULL) + return -1; + + length = XMM6260_DATA_SIZE; + buffer = malloc(length); + + rc = client->handlers->read(client->handlers->transport_data, buffer, length); + if (rc < (int) sizeof(struct rfs_hdr)) { + ipc_client_log(client, "Reading RFS header from the modem failed"); + goto error; + } + + header = (struct rfs_hdr *) buffer; + + memset(response, 0, sizeof(struct ipc_message_info)); + response->aseq = header->id; + response->group = IPC_GROUP_RFS; + response->index = header->cmd; + + if (header->len > sizeof(struct rfs_hdr)) { + response->length = header->len - sizeof(struct rfs_hdr); + response->data = malloc(response->length); + + p = (unsigned char *) response->data; + + count = rc - sizeof(struct rfs_hdr); + if (count > 0) { + memcpy(p, (void *) ((unsigned char *) buffer + sizeof(struct rfs_hdr)), count); + p += count; + } + + while (count < (int) response->length) { + rc = client->handlers->read(client->handlers->transport_data, p, response->length - count); + if (rc <= 0) { + ipc_client_log(client, "Reading RFS data from the modem failed"); + goto error; + } + + count += rc; + p += rc; + } + } + + ipc_client_log_recv(client, response, __func__); + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + if (buffer != NULL) + free(buffer); + + return rc; +} + +int xmm6260_sec_modem_ipc_open(int type) +{ + int fd; + + switch (type) { + case IPC_CLIENT_TYPE_FMT: + fd = open(XMM6260_SEC_MODEM_IPC0_DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK); + break; + case IPC_CLIENT_TYPE_RFS: + fd = open(XMM6260_SEC_MODEM_RFS0_DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK); + break; + default: + return -1; + } + + return fd; +} + +int xmm6260_sec_modem_ipc_close(int fd) +{ + if (fd < 0) + return -1; + + close(fd); + + return 0; +} + +int xmm6260_sec_modem_ipc_read(int fd, void *buffer, unsigned int length) +{ + int rc; + + if (fd < 0 || buffer == NULL || length <= 0) + return -1; + + rc = read(fd, buffer, length); + return rc; +} + +int xmm6260_sec_modem_ipc_write(int fd, void *buffer, unsigned int length) +{ + int rc; + + if (fd < 0 || buffer == NULL || length <= 0) + return -1; + + rc = write(fd, buffer, length); + return rc; +} + +int xmm6260_sec_modem_ipc_poll(int fd, struct timeval *timeout) +{ + fd_set fds; + int rc; + int status; + + if (fd < 0) + return -1; + + FD_ZERO(&fds); + FD_SET(fd, &fds); + + rc = select(fd + 1, &fds, NULL, NULL, timeout); + if (FD_ISSET(fd, &fds)) { + status = ioctl(fd, IOCTL_MODEM_STATUS, 0); + if (status != STATE_ONLINE && status != STATE_BOOTING) + return 0; + } + + return rc; +} + +char *xmm6260_sec_modem_ipc_gprs_get_iface(int cid) +{ + char *iface = NULL; + + if (cid > XMM6260_SEC_MODEM_GPRS_IFACE_COUNT) + return NULL; + + asprintf(&iface, "%s%d", XMM6260_SEC_MODEM_GPRS_IFACE_PREFIX, cid - 1); + + return iface; +} + +int xmm6260_sec_modem_ipc_gprs_get_capabilities(struct ipc_client_gprs_capabilities *capabilities) +{ + if (capabilities == NULL) + return -1; + + capabilities->port_list = 0; + capabilities->cid_max = XMM6260_SEC_MODEM_GPRS_IFACE_COUNT; + + return 0; +} + +// vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/device/xmm6260/xmm6260_sec_modem.h b/samsung-ipc/device/xmm6260/xmm6260_sec_modem.h new file mode 100644 index 0000000..fc6082b --- /dev/null +++ b/samsung-ipc/device/xmm6260/xmm6260_sec_modem.h @@ -0,0 +1,60 @@ +/* + * 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 . + * + */ + +#ifndef __XMM6260_SEC_MODEM_H__ +#define __XMM6260_SEC_MODEM_H__ + +#define XMM6260_SEC_MODEM_BOOT0_DEVICE "/dev/umts_boot0" +#define XMM6260_SEC_MODEM_BOOT1_DEVICE "/dev/umts_boot1" +#define XMM6260_SEC_MODEM_IPC0_DEVICE "/dev/umts_ipc0" +#define XMM6260_SEC_MODEM_RFS0_DEVICE "/dev/umts_rfs0" +#define XMM6260_SEC_MODEM_LINK_PM_DEVICE "/dev/link_pm" +#define XMM6260_SEC_MODEM_EHCI_POWER_SYSFS "/sys/devices/platform/s5p-ehci/ehci_power" +#define XMM6260_SEC_MODEM_OHCI_POWER_SYSFS "/sys/devices/platform/s5p-ehci/ohci_power" + +#define XMM6260_SEC_MODEM_GPRS_IFACE_PREFIX "rmnet" +#define XMM6260_SEC_MODEM_GPRS_IFACE_COUNT 3 + +int xmm6260_sec_modem_power(int device_fd, int power); +int xmm6260_sec_modem_boot_power(int device_fd, int power); +int xmm6260_sec_modem_status_online_wait(int device_fd); +int xmm6260_sec_modem_hci_power(int power); +int xmm6260_sec_modem_link_control_enable(int device_fd, int enable); +int xmm6260_sec_modem_link_control_active(int device_fd, int active); +int xmm6260_sec_modem_link_connected_wait(int device_fd); +int xmm6260_sec_modem_link_get_hostwake_wait(int device_fd); + +int xmm6260_sec_modem_ipc_fmt_send(struct ipc_client *client, struct ipc_message_info *request); +int xmm6260_sec_modem_ipc_fmt_recv(struct ipc_client *client, struct ipc_message_info *response); +int xmm6260_sec_modem_ipc_rfs_send(struct ipc_client *client, struct ipc_message_info *request); +int xmm6260_sec_modem_ipc_rfs_recv(struct ipc_client *client, struct ipc_message_info *response); + +int xmm6260_sec_modem_ipc_open(int type); +int xmm6260_sec_modem_ipc_close(int fd); +int xmm6260_sec_modem_ipc_read(int fd, void *buffer, unsigned int length); +int xmm6260_sec_modem_ipc_write(int fd, void *buffer, unsigned int length); +int xmm6260_sec_modem_ipc_poll(int fd, struct timeval *timeout); + +char *xmm6260_sec_modem_ipc_gprs_get_iface(int cid); +int xmm6260_sec_modem_ipc_gprs_get_capabilities(struct ipc_client_gprs_capabilities *capabilities); + +#endif + +// vim:ts=4:sw=4:expandtab -- cgit v1.1