Loading drivers/bus/mhi/core/mhi_boot.c +119 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,125 @@ #include <linux/mhi.h> #include "mhi_internal.h" static void mhi_process_sfr(struct mhi_controller *mhi_cntrl, struct file_info *info) { struct mhi_buf *mhi_buf = mhi_cntrl->rddm_image->mhi_buf; u8 *sfr_buf, *file_offset = info->file_offset; u32 file_size = info->file_size; u32 rem_seg_len = info->rem_seg_len; u32 seg_idx = info->seg_idx; sfr_buf = kzalloc(file_size + 1, GFP_KERNEL); if (!sfr_buf) return; while (file_size) { /* file offset starting from seg base */ if (!rem_seg_len) { file_offset = mhi_buf[seg_idx].buf; if (file_size > mhi_buf[seg_idx].len) rem_seg_len = mhi_buf[seg_idx].len; else rem_seg_len = file_size; } if (file_size <= rem_seg_len) { memcpy(sfr_buf, file_offset, file_size); break; } memcpy(sfr_buf, file_offset, rem_seg_len); sfr_buf += rem_seg_len; file_size -= rem_seg_len; rem_seg_len = 0; seg_idx++; if (seg_idx == mhi_cntrl->rddm_image->entries) { MHI_ERR("invalid size for SFR file\n"); goto err; } } sfr_buf[info->file_size] = '\0'; /* force sfr string to log in kernel msg */ MHI_ERR("%s\n", sfr_buf); err: kfree(sfr_buf); } static int mhi_find_next_file_offset(struct mhi_controller *mhi_cntrl, struct file_info *info, struct rddm_table_info *table_info) { struct mhi_buf *mhi_buf = mhi_cntrl->rddm_image->mhi_buf; if (info->rem_seg_len >= table_info->size) { info->file_offset += table_info->size; info->rem_seg_len -= table_info->size; return 0; } info->file_size = table_info->size - info->rem_seg_len; info->rem_seg_len = 0; /* iterate over segments until eof is reached */ while (info->file_size) { info->seg_idx++; if (info->seg_idx == mhi_cntrl->rddm_image->entries) { MHI_ERR("invalid size for file %s\n", table_info->file_name); return -EINVAL; } if (info->file_size > mhi_buf[info->seg_idx].len) { info->file_size -= mhi_buf[info->seg_idx].len; } else { info->file_offset = mhi_buf[info->seg_idx].buf + info->file_size; info->rem_seg_len = mhi_buf[info->seg_idx].len - info->file_size; info->file_size = 0; } } return 0; } void mhi_dump_sfr(struct mhi_controller *mhi_cntrl) { struct mhi_buf *mhi_buf = mhi_cntrl->rddm_image->mhi_buf; struct rddm_header *rddm_header = (struct rddm_header *)mhi_buf->buf; struct rddm_table_info *table_info; struct file_info info = {0}; u32 table_size, n; if (rddm_header->header_size > sizeof(*rddm_header) || rddm_header->header_size < 8) { MHI_ERR("invalid reported header size %u\n", rddm_header->header_size); return; } table_size = (rddm_header->header_size - 8) / sizeof(*table_info); if (!table_size) { MHI_ERR("invalid rddm table size %u\n", table_size); return; } info.file_offset = (u8 *)rddm_header + rddm_header->header_size; info.rem_seg_len = mhi_buf[0].len - rddm_header->header_size; for (n = 0; n < table_size; n++) { table_info = &rddm_header->table_info[n]; if (!strcmp(table_info->file_name, "Q6-SFR.bin")) { info.file_size = table_info->size; mhi_process_sfr(mhi_cntrl, &info); return; } if (mhi_find_next_file_offset(mhi_cntrl, &info, table_info)) return; } } EXPORT_SYMBOL(mhi_dump_sfr); /* setup rddm vector table for rddm transfer and program rxvec */ void mhi_rddm_prepare(struct mhi_controller *mhi_cntrl, Loading include/linux/mhi.h +52 −0 Original line number Diff line number Diff line Loading @@ -139,6 +139,52 @@ struct image_info { u32 entries; }; /* rddm header info */ #define MAX_RDDM_TABLE_SIZE 6 /** * struct rddm_table_info - rddm table info * @base_address - Start offset of the file * @actual_phys_address - phys addr offset of file * @size - size of file * @description - file description * @file_name - name of file */ struct rddm_table_info { u64 base_address; u64 actual_phys_address; u64 size; char description[20]; char file_name[20]; }; /** * struct rddm_header - rddm header * @version - header ver * @header_size - size of header * @rddm_table_info - array of rddm table info */ struct rddm_header { u32 version; u32 header_size; struct rddm_table_info table_info[MAX_RDDM_TABLE_SIZE]; }; /** * struct file_info - keeping track of file info while traversing the rddm * table header * @file_offset - current file offset * @seg_idx - mhi buf seg array index * @rem_seg_len - remaining length of the segment containing current file */ struct file_info { u8 *file_offset; u32 file_size; u32 seg_idx; u32 rem_seg_len; }; /** * struct mhi_controller - Master controller structure for external modem * @dev: Device associated with this controller Loading Loading @@ -689,6 +735,12 @@ int mhi_download_rddm_img(struct mhi_controller *mhi_cntrl, bool in_panic); */ int mhi_force_rddm_mode(struct mhi_controller *mhi_cntrl); /** * mhi_dump_sfr - Print SFR string from RDDM table. * @mhi_cntrl: MHI controller */ void mhi_dump_sfr(struct mhi_controller *mhi_cntrl); /** * mhi_get_remote_time_sync - Get external soc time relative to local soc time * using MMIO method. Loading Loading
drivers/bus/mhi/core/mhi_boot.c +119 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,125 @@ #include <linux/mhi.h> #include "mhi_internal.h" static void mhi_process_sfr(struct mhi_controller *mhi_cntrl, struct file_info *info) { struct mhi_buf *mhi_buf = mhi_cntrl->rddm_image->mhi_buf; u8 *sfr_buf, *file_offset = info->file_offset; u32 file_size = info->file_size; u32 rem_seg_len = info->rem_seg_len; u32 seg_idx = info->seg_idx; sfr_buf = kzalloc(file_size + 1, GFP_KERNEL); if (!sfr_buf) return; while (file_size) { /* file offset starting from seg base */ if (!rem_seg_len) { file_offset = mhi_buf[seg_idx].buf; if (file_size > mhi_buf[seg_idx].len) rem_seg_len = mhi_buf[seg_idx].len; else rem_seg_len = file_size; } if (file_size <= rem_seg_len) { memcpy(sfr_buf, file_offset, file_size); break; } memcpy(sfr_buf, file_offset, rem_seg_len); sfr_buf += rem_seg_len; file_size -= rem_seg_len; rem_seg_len = 0; seg_idx++; if (seg_idx == mhi_cntrl->rddm_image->entries) { MHI_ERR("invalid size for SFR file\n"); goto err; } } sfr_buf[info->file_size] = '\0'; /* force sfr string to log in kernel msg */ MHI_ERR("%s\n", sfr_buf); err: kfree(sfr_buf); } static int mhi_find_next_file_offset(struct mhi_controller *mhi_cntrl, struct file_info *info, struct rddm_table_info *table_info) { struct mhi_buf *mhi_buf = mhi_cntrl->rddm_image->mhi_buf; if (info->rem_seg_len >= table_info->size) { info->file_offset += table_info->size; info->rem_seg_len -= table_info->size; return 0; } info->file_size = table_info->size - info->rem_seg_len; info->rem_seg_len = 0; /* iterate over segments until eof is reached */ while (info->file_size) { info->seg_idx++; if (info->seg_idx == mhi_cntrl->rddm_image->entries) { MHI_ERR("invalid size for file %s\n", table_info->file_name); return -EINVAL; } if (info->file_size > mhi_buf[info->seg_idx].len) { info->file_size -= mhi_buf[info->seg_idx].len; } else { info->file_offset = mhi_buf[info->seg_idx].buf + info->file_size; info->rem_seg_len = mhi_buf[info->seg_idx].len - info->file_size; info->file_size = 0; } } return 0; } void mhi_dump_sfr(struct mhi_controller *mhi_cntrl) { struct mhi_buf *mhi_buf = mhi_cntrl->rddm_image->mhi_buf; struct rddm_header *rddm_header = (struct rddm_header *)mhi_buf->buf; struct rddm_table_info *table_info; struct file_info info = {0}; u32 table_size, n; if (rddm_header->header_size > sizeof(*rddm_header) || rddm_header->header_size < 8) { MHI_ERR("invalid reported header size %u\n", rddm_header->header_size); return; } table_size = (rddm_header->header_size - 8) / sizeof(*table_info); if (!table_size) { MHI_ERR("invalid rddm table size %u\n", table_size); return; } info.file_offset = (u8 *)rddm_header + rddm_header->header_size; info.rem_seg_len = mhi_buf[0].len - rddm_header->header_size; for (n = 0; n < table_size; n++) { table_info = &rddm_header->table_info[n]; if (!strcmp(table_info->file_name, "Q6-SFR.bin")) { info.file_size = table_info->size; mhi_process_sfr(mhi_cntrl, &info); return; } if (mhi_find_next_file_offset(mhi_cntrl, &info, table_info)) return; } } EXPORT_SYMBOL(mhi_dump_sfr); /* setup rddm vector table for rddm transfer and program rxvec */ void mhi_rddm_prepare(struct mhi_controller *mhi_cntrl, Loading
include/linux/mhi.h +52 −0 Original line number Diff line number Diff line Loading @@ -139,6 +139,52 @@ struct image_info { u32 entries; }; /* rddm header info */ #define MAX_RDDM_TABLE_SIZE 6 /** * struct rddm_table_info - rddm table info * @base_address - Start offset of the file * @actual_phys_address - phys addr offset of file * @size - size of file * @description - file description * @file_name - name of file */ struct rddm_table_info { u64 base_address; u64 actual_phys_address; u64 size; char description[20]; char file_name[20]; }; /** * struct rddm_header - rddm header * @version - header ver * @header_size - size of header * @rddm_table_info - array of rddm table info */ struct rddm_header { u32 version; u32 header_size; struct rddm_table_info table_info[MAX_RDDM_TABLE_SIZE]; }; /** * struct file_info - keeping track of file info while traversing the rddm * table header * @file_offset - current file offset * @seg_idx - mhi buf seg array index * @rem_seg_len - remaining length of the segment containing current file */ struct file_info { u8 *file_offset; u32 file_size; u32 seg_idx; u32 rem_seg_len; }; /** * struct mhi_controller - Master controller structure for external modem * @dev: Device associated with this controller Loading Loading @@ -689,6 +735,12 @@ int mhi_download_rddm_img(struct mhi_controller *mhi_cntrl, bool in_panic); */ int mhi_force_rddm_mode(struct mhi_controller *mhi_cntrl); /** * mhi_dump_sfr - Print SFR string from RDDM table. * @mhi_cntrl: MHI controller */ void mhi_dump_sfr(struct mhi_controller *mhi_cntrl); /** * mhi_get_remote_time_sync - Get external soc time relative to local soc time * using MMIO method. Loading