123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193 |
- /*
- * Synaptics TCM touchscreen driver
- *
- * Copyright (C) 2017-2019 Synaptics Incorporated. All rights reserved.
- *
- * Copyright (C) 2017-2019 Scott Lin <[email protected]>
- *
- * 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.
- *
- * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
- * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
- * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
- * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
- * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
- * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
- * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
- * DOLLARS.
- */
- #include <linux/crc32.h>
- #include <linux/firmware.h>
- #include "synaptics_tcm_core.h"
- #define STARTUP_REFLASH
- #define FORCE_REFLASH false
- #define ENABLE_SYSFS_INTERFACE true
- #define SYSFS_DIR_NAME "reflash"
- #define CUSTOM_DIR_NAME "custom"
- #define FW_IMAGE_NAME "synaptics_firmware.img"
- #define BOOT_CONFIG_ID "BOOT_CONFIG"
- #define APP_CODE_ID "APP_CODE"
- #define PROD_TEST_ID "APP_PROD_TEST"
- #define APP_CONFIG_ID "APP_CONFIG"
- #define DISP_CONFIG_ID "DISPLAY"
- #define FB_READY_COUNT 2
- #define FB_READY_WAIT_MS 100
- #define FB_READY_TIMEOUT_S 80
- #define IMAGE_FILE_MAGIC_VALUE 0x4818472b
- #define FLASH_AREA_MAGIC_VALUE 0x7c05e516
- #define BOOT_CONFIG_SIZE 8
- #define BOOT_CONFIG_SLOTS 16
- #define IMAGE_BUF_SIZE (512 * 1024)
- #define ERASE_FLASH_DELAY_MS 500
- #define WRITE_FLASH_DELAY_MS 20
- #define REFLASH (1 << 0)
- #define FORCE_UPDATE (1 << 1)
- #define APP_CFG_UPDATE (1 << 2)
- #define DISP_CFG_UPDATE (1 << 3)
- #define BOOT_CFG_UPDATE (1 << 4)
- #define BOOT_CFG_LOCKDOWN (1 << 5)
- #define reflash_write(p_name) \
- static int reflash_write_##p_name(void) \
- { \
- int retval; \
- unsigned int size; \
- unsigned int flash_addr; \
- struct syna_tcm_hcd *tcm_hcd = reflash_hcd->tcm_hcd; \
- const unsigned char *data; \
- \
- data = reflash_hcd->image_info.p_name.data; \
- size = reflash_hcd->image_info.p_name.size; \
- flash_addr = reflash_hcd->image_info.p_name.flash_addr; \
- \
- retval = reflash_write_flash(flash_addr, data, size); \
- if (retval < 0) { \
- LOGE(tcm_hcd->pdev->dev.parent, \
- "Failed to write to flash\n"); \
- return retval; \
- } \
- \
- return 0; \
- }
- #define reflash_erase(p_name) \
- static int reflash_erase_##p_name(void) \
- { \
- int retval; \
- unsigned int size; \
- unsigned int flash_addr; \
- unsigned int page_start; \
- unsigned int page_count; \
- struct syna_tcm_hcd *tcm_hcd = reflash_hcd->tcm_hcd; \
- \
- flash_addr = reflash_hcd->image_info.p_name.flash_addr; \
- \
- page_start = flash_addr / reflash_hcd->page_size; \
- \
- size = reflash_hcd->image_info.p_name.size; \
- page_count = ceil_div(size, reflash_hcd->page_size); \
- \
- LOGD(tcm_hcd->pdev->dev.parent, \
- "Page start = %d\n", \
- page_start); \
- \
- LOGD(tcm_hcd->pdev->dev.parent, \
- "Page count = %d\n", \
- page_count); \
- \
- retval = reflash_erase_flash(page_start, page_count); \
- if (retval < 0) { \
- LOGE(tcm_hcd->pdev->dev.parent, \
- "Failed to erase flash pages\n"); \
- return retval; \
- } \
- \
- return 0; \
- }
- #define reflash_update(p_name) \
- static int reflash_update_##p_name(bool reset) \
- { \
- int retval; \
- struct syna_tcm_hcd *tcm_hcd = reflash_hcd->tcm_hcd; \
- \
- retval = reflash_set_up_flash_access(); \
- if (retval < 0) { \
- LOGE(tcm_hcd->pdev->dev.parent, \
- "Failed to set up flash access\n"); \
- return retval; \
- } \
- \
- tcm_hcd->update_watchdog(tcm_hcd, false); \
- \
- retval = reflash_check_##p_name(); \
- if (retval < 0) { \
- LOGE(tcm_hcd->pdev->dev.parent, \
- "Failed "#p_name" partition check\n"); \
- reset = true; \
- goto reset; \
- } \
- \
- retval = reflash_erase_##p_name(); \
- if (retval < 0) { \
- LOGE(tcm_hcd->pdev->dev.parent, \
- "Failed to erase "#p_name" partition\n"); \
- reset = true; \
- goto reset; \
- } \
- \
- LOGN(tcm_hcd->pdev->dev.parent, \
- "Partition erased ("#p_name")\n"); \
- \
- retval = reflash_write_##p_name(); \
- if (retval < 0) { \
- LOGE(tcm_hcd->pdev->dev.parent, \
- "Failed to write "#p_name" partition\n"); \
- reset = true; \
- goto reset; \
- } \
- \
- LOGN(tcm_hcd->pdev->dev.parent, \
- "Partition written ("#p_name")\n"); \
- \
- retval = 0; \
- \
- reset: \
- if (!reset) \
- goto exit; \
- \
- if (tcm_hcd->reset(tcm_hcd, false, true) < 0) { \
- LOGE(tcm_hcd->pdev->dev.parent, \
- "Failed to do reset\n"); \
- } \
- \
- exit: \
- tcm_hcd->update_watchdog(tcm_hcd, true); \
- \
- return retval; \
- }
- #define reflash_show_data() \
- { \
- LOCK_BUFFER(reflash_hcd->read); \
- \
- readlen = MIN(count, reflash_hcd->read.data_length - pos); \
- \
- retval = secure_memcpy(buf, \
- count, \
- &reflash_hcd->read.buf[pos], \
- reflash_hcd->read.buf_size - pos, \
- readlen); \
- if (retval < 0) { \
- LOGE(tcm_hcd->pdev->dev.parent, \
- "Failed to copy read data\n"); \
- } else { \
- retval = readlen; \
- } \
- \
- UNLOCK_BUFFER(reflash_hcd->read); \
- }
- enum update_area {
- NONE = 0,
- FIRMWARE_CONFIG,
- CONFIG_ONLY,
- };
- struct app_config_header {
- unsigned short magic_value[4];
- unsigned char checksum[4];
- unsigned char length[2];
- unsigned char build_id[4];
- unsigned char customer_config_id[16];
- };
- struct area_descriptor {
- unsigned char magic_value[4];
- unsigned char id_string[16];
- unsigned char flags[4];
- unsigned char flash_addr_words[4];
- unsigned char length[4];
- unsigned char checksum[4];
- };
- struct block_data {
- const unsigned char *data;
- unsigned int size;
- unsigned int flash_addr;
- };
- struct image_info {
- struct block_data boot_config;
- struct block_data app_firmware;
- struct block_data prod_test_firmware;
- struct block_data app_config;
- struct block_data disp_config;
- };
- struct image_header {
- unsigned char magic_value[4];
- unsigned char num_of_areas[4];
- };
- struct boot_config {
- union {
- unsigned char i2c_address;
- struct {
- unsigned char cpha:1;
- unsigned char cpol:1;
- unsigned char word0_b2__7:6;
- } __packed;
- };
- unsigned char attn_polarity:1;
- unsigned char attn_drive:2;
- unsigned char attn_pullup:1;
- unsigned char word0_b12__14:3;
- unsigned char used:1;
- unsigned short customer_part_id;
- unsigned short boot_timeout;
- unsigned short continue_on_reset:1;
- unsigned short word3_b1__15:15;
- } __packed;
- struct reflash_hcd {
- bool force_update;
- bool disp_cfg_update;
- const unsigned char *image;
- unsigned char *image_buf;
- unsigned int image_size;
- unsigned int page_size;
- unsigned int write_block_size;
- unsigned int max_write_payload_size;
- const struct firmware *fw_entry;
- struct mutex reflash_mutex;
- struct kobject *sysfs_dir;
- struct kobject *custom_dir;
- struct work_struct work;
- struct workqueue_struct *workqueue;
- struct image_info image_info;
- struct syna_tcm_buffer out;
- struct syna_tcm_buffer resp;
- struct syna_tcm_buffer read;
- struct syna_tcm_hcd *tcm_hcd;
- };
- DECLARE_COMPLETION(reflash_remove_complete);
- static struct reflash_hcd *reflash_hcd;
- static int reflash_get_fw_image(void);
- static int reflash_read_data(enum flash_area area, bool run_app_firmware,
- struct syna_tcm_buffer *output);
- static int reflash_update_custom_otp(const unsigned char *data,
- unsigned int offset, unsigned int datalen);
- static int reflash_update_custom_lcm(const unsigned char *data,
- unsigned int offset, unsigned int datalen);
- static int reflash_update_custom_oem(const unsigned char *data,
- unsigned int offset, unsigned int datalen);
- static int reflash_update_boot_config(bool lock);
- static int reflash_update_app_config(bool reset);
- static int reflash_update_disp_config(bool reset);
- static int reflash_do_reflash(void);
- STORE_PROTOTYPE(reflash, reflash);
- static struct device_attribute *attrs[] = {
- ATTRIFY(reflash),
- };
- static ssize_t reflash_sysfs_image_store(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count);
- static ssize_t reflash_sysfs_lockdown_show(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count);
- static ssize_t reflash_sysfs_lockdown_store(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count);
- static ssize_t reflash_sysfs_lcm_show(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count);
- static ssize_t reflash_sysfs_lcm_store(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count);
- static ssize_t reflash_sysfs_oem_show(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count);
- static ssize_t reflash_sysfs_oem_store(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count);
- static struct bin_attribute bin_attrs[] = {
- {
- .attr = {
- .name = "image",
- .mode = 0220,
- },
- .size = 0,
- .write = reflash_sysfs_image_store,
- },
- {
- .attr = {
- .name = "lockdown",
- .mode = 0664,
- },
- .size = 0,
- .read = reflash_sysfs_lockdown_show,
- .write = reflash_sysfs_lockdown_store,
- },
- {
- .attr = {
- .name = "lcm",
- .mode = 0664,
- },
- .size = 0,
- .read = reflash_sysfs_lcm_show,
- .write = reflash_sysfs_lcm_store,
- },
- {
- .attr = {
- .name = "oem",
- .mode = 0664,
- },
- .size = 0,
- .read = reflash_sysfs_oem_show,
- .write = reflash_sysfs_oem_store,
- },
- };
- static ssize_t reflash_sysfs_reflash_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
- {
- int retval;
- unsigned int input;
- struct syna_tcm_hcd *tcm_hcd = reflash_hcd->tcm_hcd;
- if (kstrtouint(buf, 10, &input))
- return -EINVAL;
- mutex_lock(&tcm_hcd->extif_mutex);
- pm_stay_awake(&tcm_hcd->pdev->dev);
- mutex_lock(&reflash_hcd->reflash_mutex);
- if (reflash_hcd->image_size != 0)
- reflash_hcd->image = reflash_hcd->image_buf;
- reflash_hcd->force_update = input & FORCE_UPDATE ? true : false;
- if (input & REFLASH || input & FORCE_UPDATE) {
- retval = reflash_do_reflash();
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to do reflash\n");
- goto exit;
- }
- }
- if ((input & ~(REFLASH | FORCE_UPDATE)) == 0) {
- retval = count;
- goto exit;
- }
- retval = reflash_get_fw_image();
- if (retval < 0) {
- LOGD(tcm_hcd->pdev->dev.parent,
- "Failed to get firmware image\n");
- goto exit;
- }
- if (input & BOOT_CFG_LOCKDOWN) {
- retval = reflash_update_boot_config(true);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to lockdown boot config\n");
- goto exit;
- }
- } else if (input & BOOT_CFG_UPDATE) {
- retval = reflash_update_boot_config(false);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to update boot config\n");
- goto exit;
- }
- }
- if (input & REFLASH || input & FORCE_UPDATE) {
- retval = count;
- goto exit;
- }
- if (input & DISP_CFG_UPDATE) {
- if (input & APP_CFG_UPDATE)
- retval = reflash_update_disp_config(false);
- else
- retval = reflash_update_disp_config(true);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to reflash display config\n");
- goto exit;
- }
- }
- if (input & APP_CFG_UPDATE) {
- retval = reflash_update_app_config(true);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to reflash application config\n");
- goto exit;
- }
- }
- retval = count;
- exit:
- if (reflash_hcd->fw_entry) {
- release_firmware(reflash_hcd->fw_entry);
- reflash_hcd->fw_entry = NULL;
- }
- reflash_hcd->image = NULL;
- reflash_hcd->image_size = 0;
- reflash_hcd->force_update = FORCE_REFLASH;
- mutex_unlock(&reflash_hcd->reflash_mutex);
- pm_relax(&tcm_hcd->pdev->dev);
- mutex_unlock(&tcm_hcd->extif_mutex);
- return retval;
- }
- static ssize_t reflash_sysfs_image_store(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count)
- {
- int retval;
- struct syna_tcm_hcd *tcm_hcd = reflash_hcd->tcm_hcd;
- mutex_lock(&tcm_hcd->extif_mutex);
- retval = secure_memcpy(&reflash_hcd->image_buf[pos],
- IMAGE_BUF_SIZE - pos,
- buf,
- count,
- count);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to copy firmware image data\n");
- reflash_hcd->image_size = 0;
- goto exit;
- }
- reflash_hcd->image_size = pos + count;
- retval = count;
- exit:
- mutex_unlock(&tcm_hcd->extif_mutex);
- return retval;
- }
- static ssize_t reflash_sysfs_lockdown_show(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count)
- {
- int retval;
- unsigned int readlen;
- struct syna_tcm_hcd *tcm_hcd = reflash_hcd->tcm_hcd;
- mutex_lock(&tcm_hcd->extif_mutex);
- mutex_lock(&reflash_hcd->reflash_mutex);
- retval = reflash_read_data(CUSTOM_OTP, true, NULL);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to read lockdown data\n");
- goto exit;
- }
- reflash_show_data();
- exit:
- mutex_unlock(&reflash_hcd->reflash_mutex);
- mutex_unlock(&tcm_hcd->extif_mutex);
- return retval;
- }
- static ssize_t reflash_sysfs_lockdown_store(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count)
- {
- int retval;
- struct syna_tcm_hcd *tcm_hcd = reflash_hcd->tcm_hcd;
- mutex_lock(&tcm_hcd->extif_mutex);
- pm_stay_awake(&tcm_hcd->pdev->dev);
- mutex_lock(&reflash_hcd->reflash_mutex);
- retval = reflash_update_custom_otp(buf, pos, count);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to update custom OTP data\n");
- goto exit;
- }
- retval = count;
- exit:
- mutex_unlock(&reflash_hcd->reflash_mutex);
- pm_relax(&tcm_hcd->pdev->dev);
- mutex_unlock(&tcm_hcd->extif_mutex);
- return retval;
- }
- static ssize_t reflash_sysfs_lcm_show(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count)
- {
- int retval;
- unsigned int readlen;
- struct syna_tcm_hcd *tcm_hcd = reflash_hcd->tcm_hcd;
- mutex_lock(&tcm_hcd->extif_mutex);
- mutex_lock(&reflash_hcd->reflash_mutex);
- retval = reflash_read_data(CUSTOM_LCM, true, NULL);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to read LCM data\n");
- goto exit;
- }
- reflash_show_data();
- exit:
- mutex_unlock(&reflash_hcd->reflash_mutex);
- mutex_unlock(&tcm_hcd->extif_mutex);
- return retval;
- }
- static ssize_t reflash_sysfs_lcm_store(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count)
- {
- int retval;
- struct syna_tcm_hcd *tcm_hcd = reflash_hcd->tcm_hcd;
- mutex_lock(&tcm_hcd->extif_mutex);
- pm_stay_awake(&tcm_hcd->pdev->dev);
- mutex_lock(&reflash_hcd->reflash_mutex);
- retval = reflash_update_custom_lcm(buf, pos, count);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to update custom LCM data\n");
- goto exit;
- }
- retval = count;
- exit:
- mutex_unlock(&reflash_hcd->reflash_mutex);
- pm_relax(&tcm_hcd->pdev->dev);
- mutex_unlock(&tcm_hcd->extif_mutex);
- return retval;
- }
- static ssize_t reflash_sysfs_oem_show(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count)
- {
- int retval;
- unsigned int readlen;
- struct syna_tcm_hcd *tcm_hcd = reflash_hcd->tcm_hcd;
- mutex_lock(&tcm_hcd->extif_mutex);
- mutex_lock(&reflash_hcd->reflash_mutex);
- retval = reflash_read_data(CUSTOM_OEM, true, NULL);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to read OEM data\n");
- goto exit;
- }
- reflash_show_data();
- exit:
- mutex_unlock(&reflash_hcd->reflash_mutex);
- mutex_unlock(&tcm_hcd->extif_mutex);
- return retval;
- }
- static ssize_t reflash_sysfs_oem_store(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count)
- {
- int retval;
- struct syna_tcm_hcd *tcm_hcd = reflash_hcd->tcm_hcd;
- mutex_lock(&tcm_hcd->extif_mutex);
- pm_stay_awake(&tcm_hcd->pdev->dev);
- mutex_lock(&reflash_hcd->reflash_mutex);
- retval = reflash_update_custom_oem(buf, pos, count);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to update custom OEM data\n");
- goto exit;
- }
- retval = count;
- exit:
- mutex_unlock(&reflash_hcd->reflash_mutex);
- pm_relax(&tcm_hcd->pdev->dev);
- mutex_unlock(&tcm_hcd->extif_mutex);
- return retval;
- }
- static int reflash_set_up_flash_access(void)
- {
- int retval;
- unsigned int temp;
- struct syna_tcm_hcd *tcm_hcd = reflash_hcd->tcm_hcd;
- retval = tcm_hcd->identify(tcm_hcd, true);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to do identification\n");
- return retval;
- }
- if (tcm_hcd->id_info.mode == MODE_APPLICATION) {
- retval = tcm_hcd->switch_mode(tcm_hcd, FW_MODE_BOOTLOADER);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to enter bootloader mode\n");
- return retval;
- }
- }
- temp = tcm_hcd->boot_info.write_block_size_words;
- reflash_hcd->write_block_size = temp * 2;
- temp = le2_to_uint(tcm_hcd->boot_info.erase_page_size_words);
- reflash_hcd->page_size = temp * 2;
- temp = le2_to_uint(tcm_hcd->boot_info.max_write_payload_size);
- reflash_hcd->max_write_payload_size = temp;
- LOGD(tcm_hcd->pdev->dev.parent,
- "Write block size = %d\n",
- reflash_hcd->write_block_size);
- LOGD(tcm_hcd->pdev->dev.parent,
- "Page size = %d\n",
- reflash_hcd->page_size);
- LOGD(tcm_hcd->pdev->dev.parent,
- "Max write payload size = %d\n",
- reflash_hcd->max_write_payload_size);
- if (reflash_hcd->write_block_size > (tcm_hcd->wr_chunk_size - 5)) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Write size greater than available chunk space\n");
- return -EINVAL;
- }
- return 0;
- }
- static int reflash_parse_fw_image(void)
- {
- unsigned int idx;
- unsigned int addr;
- unsigned int offset;
- unsigned int length;
- unsigned int checksum;
- unsigned int flash_addr;
- unsigned int magic_value;
- unsigned int num_of_areas;
- struct image_header *header;
- struct image_info *image_info;
- struct area_descriptor *descriptor;
- struct syna_tcm_hcd *tcm_hcd = reflash_hcd->tcm_hcd;
- const unsigned char *image;
- const unsigned char *content;
- image = reflash_hcd->image;
- image_info = &reflash_hcd->image_info;
- header = (struct image_header *)image;
- reflash_hcd->disp_cfg_update = false;
- magic_value = le4_to_uint(header->magic_value);
- if (magic_value != IMAGE_FILE_MAGIC_VALUE) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Invalid image file magic value\n");
- return -EINVAL;
- }
- memset(image_info, 0x00, sizeof(*image_info));
- offset = sizeof(*header);
- num_of_areas = le4_to_uint(header->num_of_areas);
- for (idx = 0; idx < num_of_areas; idx++) {
- addr = le4_to_uint(image + offset);
- descriptor = (struct area_descriptor *)(image + addr);
- offset += 4;
- magic_value = le4_to_uint(descriptor->magic_value);
- if (magic_value != FLASH_AREA_MAGIC_VALUE)
- continue;
- length = le4_to_uint(descriptor->length);
- content = (unsigned char *)descriptor + sizeof(*descriptor);
- flash_addr = le4_to_uint(descriptor->flash_addr_words) * 2;
- checksum = le4_to_uint(descriptor->checksum);
- if (!memcmp((char *)descriptor->id_string,
- BOOT_CONFIG_ID,
- strlen(BOOT_CONFIG_ID))) {
- if (checksum != (crc32(~0, content, length) ^ ~0)) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Boot config checksum error\n");
- return -EINVAL;
- }
- image_info->boot_config.size = length;
- image_info->boot_config.data = content;
- image_info->boot_config.flash_addr = flash_addr;
- LOGD(tcm_hcd->pdev->dev.parent,
- "Boot config size = %d\n",
- length);
- LOGD(tcm_hcd->pdev->dev.parent,
- "Boot config flash address = 0x%08x\n",
- flash_addr);
- } else if (!memcmp((char *)descriptor->id_string,
- APP_CODE_ID,
- strlen(APP_CODE_ID))) {
- if (checksum != (crc32(~0, content, length) ^ ~0)) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "APP firmware checksum error\n");
- return -EINVAL;
- }
- image_info->app_firmware.size = length;
- image_info->app_firmware.data = content;
- image_info->app_firmware.flash_addr = flash_addr;
- LOGD(tcm_hcd->pdev->dev.parent,
- "Application firmware size = %d\n",
- length);
- LOGD(tcm_hcd->pdev->dev.parent,
- "Application firmware flash address = 0x%08x\n",
- flash_addr);
- } else if (!memcmp((char *)descriptor->id_string,
- PROD_TEST_ID,
- strlen(PROD_TEST_ID))) {
- if (checksum != (crc32(~0, content, length) ^ ~0)) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Production test checksum error\n");
- return -EINVAL;
- }
- image_info->prod_test_firmware.size = length;
- image_info->prod_test_firmware.data = content;
- image_info->prod_test_firmware.flash_addr = flash_addr;
- LOGD(tcm_hcd->pdev->dev.parent,
- "Production test firmware size = %d\n",
- length);
- LOGD(tcm_hcd->pdev->dev.parent,
- "Production test flash address = 0x%08x\n",
- flash_addr);
- } else if (!memcmp((char *)descriptor->id_string,
- APP_CONFIG_ID,
- strlen(APP_CONFIG_ID))) {
- if (checksum != (crc32(~0, content, length) ^ ~0)) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Application config checksum error\n");
- return -EINVAL;
- }
- image_info->app_config.size = length;
- image_info->app_config.data = content;
- image_info->app_config.flash_addr = flash_addr;
- LOGD(tcm_hcd->pdev->dev.parent,
- "Application config size = %d\n",
- length);
- LOGD(tcm_hcd->pdev->dev.parent,
- "Application config flash address = 0x%08x\n",
- flash_addr);
- } else if (!memcmp((char *)descriptor->id_string,
- DISP_CONFIG_ID,
- strlen(DISP_CONFIG_ID))) {
- if (checksum != (crc32(~0, content, length) ^ ~0)) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Display config checksum error\n");
- return -EINVAL;
- }
- reflash_hcd->disp_cfg_update = true;
- image_info->disp_config.size = length;
- image_info->disp_config.data = content;
- image_info->disp_config.flash_addr = flash_addr;
- LOGD(tcm_hcd->pdev->dev.parent,
- "Display config size = %d\n",
- length);
- LOGD(tcm_hcd->pdev->dev.parent,
- "Display config flash address = 0x%08x\n",
- flash_addr);
- }
- }
- return 0;
- }
- static int reflash_get_fw_image(void)
- {
- int retval;
- const char *fw_name;
- struct syna_tcm_hcd *tcm_hcd = reflash_hcd->tcm_hcd;
- const struct syna_tcm_board_data *bdata = tcm_hcd->hw_if->bdata;
- if (bdata->fw_name)
- fw_name = bdata->fw_name;
- else
- fw_name = FW_IMAGE_NAME;
- if (reflash_hcd->image == NULL) {
- retval = request_firmware(&reflash_hcd->fw_entry, fw_name,
- tcm_hcd->pdev->dev.parent);
- if (retval < 0) {
- LOGD(tcm_hcd->pdev->dev.parent,
- "Failed to request %s\n",
- fw_name);
- return retval;
- }
- LOGD(tcm_hcd->pdev->dev.parent,
- "Firmware image size = %d\n",
- (unsigned int)reflash_hcd->fw_entry->size);
- reflash_hcd->image = reflash_hcd->fw_entry->data;
- reflash_hcd->image_size = reflash_hcd->fw_entry->size;
- }
- retval = reflash_parse_fw_image();
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to parse firmware image\n");
- return retval;
- }
- return 0;
- }
- static enum update_area reflash_compare_id_info(void)
- {
- enum update_area update_area;
- unsigned int idx;
- unsigned int image_fw_id;
- unsigned int device_fw_id;
- unsigned char *image_config_id;
- unsigned char *device_config_id;
- struct app_config_header *header;
- struct syna_tcm_hcd *tcm_hcd = reflash_hcd->tcm_hcd;
- const unsigned char *app_config_data;
- update_area = NONE;
- if (reflash_hcd->image_info.app_config.size < sizeof(*header)) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Invalid application config in image file\n");
- goto exit;
- }
- app_config_data = reflash_hcd->image_info.app_config.data;
- header = (struct app_config_header *)app_config_data;
- if (reflash_hcd->force_update) {
- update_area = FIRMWARE_CONFIG;
- goto exit;
- }
- if (tcm_hcd->id_info.mode != MODE_APPLICATION) {
- update_area = FIRMWARE_CONFIG;
- goto exit;
- }
- image_fw_id = le4_to_uint(header->build_id);
- device_fw_id = tcm_hcd->packrat_number;
- if (image_fw_id > device_fw_id) {
- LOGN(tcm_hcd->pdev->dev.parent,
- "Image firmware ID newer than device firmware ID\n");
- update_area = FIRMWARE_CONFIG;
- goto exit;
- } else if (image_fw_id < device_fw_id) {
- LOGN(tcm_hcd->pdev->dev.parent,
- "Image firmware ID older than device firmware ID\n");
- update_area = NONE;
- goto exit;
- }
- image_config_id = header->customer_config_id;
- device_config_id = tcm_hcd->app_info.customer_config_id;
- for (idx = 0; idx < 16; idx++) {
- if (image_config_id[idx] > device_config_id[idx]) {
- LOGN(tcm_hcd->pdev->dev.parent,
- "Image config ID newer than device's ID\n");
- update_area = CONFIG_ONLY;
- goto exit;
- } else if (image_config_id[idx] < device_config_id[idx]) {
- LOGN(tcm_hcd->pdev->dev.parent,
- "Image config ID older than device's ID\n");
- update_area = NONE;
- goto exit;
- }
- }
- update_area = NONE;
- exit:
- if (update_area == NONE)
- LOGD(tcm_hcd->pdev->dev.parent, "No need to do reflash\n");
- else
- LOGD(tcm_hcd->pdev->dev.parent,
- "Updating %s\n",
- update_area == FIRMWARE_CONFIG ?
- "firmware and config" :
- "config only");
- return update_area;
- }
- static int reflash_read_flash(unsigned int address, unsigned char *data,
- unsigned int datalen)
- {
- int retval;
- unsigned int length_words;
- unsigned int flash_addr_words;
- struct syna_tcm_hcd *tcm_hcd = reflash_hcd->tcm_hcd;
- LOCK_BUFFER(reflash_hcd->out);
- retval = syna_tcm_alloc_mem(tcm_hcd,
- &reflash_hcd->out,
- 6);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to allocate memory for reflash_hcd->out.buf\n");
- UNLOCK_BUFFER(reflash_hcd->out);
- return retval;
- }
- length_words = datalen / 2;
- flash_addr_words = address / 2;
- reflash_hcd->out.buf[0] = (unsigned char)flash_addr_words;
- reflash_hcd->out.buf[1] = (unsigned char)(flash_addr_words >> 8);
- reflash_hcd->out.buf[2] = (unsigned char)(flash_addr_words >> 16);
- reflash_hcd->out.buf[3] = (unsigned char)(flash_addr_words >> 24);
- reflash_hcd->out.buf[4] = (unsigned char)length_words;
- reflash_hcd->out.buf[5] = (unsigned char)(length_words >> 8);
- LOCK_BUFFER(reflash_hcd->resp);
- retval = tcm_hcd->write_message(tcm_hcd,
- CMD_READ_FLASH,
- reflash_hcd->out.buf,
- 6,
- &reflash_hcd->resp.buf,
- &reflash_hcd->resp.buf_size,
- &reflash_hcd->resp.data_length,
- NULL,
- 0);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to write command %s\n",
- STR(CMD_READ_FLASH));
- UNLOCK_BUFFER(reflash_hcd->resp);
- UNLOCK_BUFFER(reflash_hcd->out);
- return retval;
- }
- UNLOCK_BUFFER(reflash_hcd->out);
- if (reflash_hcd->resp.data_length != datalen) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to read requested length\n");
- UNLOCK_BUFFER(reflash_hcd->resp);
- return -EIO;
- }
- retval = secure_memcpy(data,
- datalen,
- reflash_hcd->resp.buf,
- reflash_hcd->resp.buf_size,
- datalen);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to copy read data\n");
- UNLOCK_BUFFER(reflash_hcd->resp);
- return retval;
- }
- UNLOCK_BUFFER(reflash_hcd->resp);
- return 0;
- }
- static int reflash_read_data(enum flash_area area, bool run_app_firmware,
- struct syna_tcm_buffer *output)
- {
- int retval;
- unsigned int temp;
- unsigned int addr;
- unsigned int length;
- struct syna_tcm_app_info *app_info;
- struct syna_tcm_boot_info *boot_info;
- struct syna_tcm_hcd *tcm_hcd = reflash_hcd->tcm_hcd;
- switch (area) {
- case CUSTOM_LCM:
- case CUSTOM_OEM:
- case PPDT:
- retval = tcm_hcd->get_data_location(tcm_hcd,
- area,
- &addr,
- &length);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to get data location\n");
- return retval;
- }
- break;
- default:
- break;
- }
- retval = reflash_set_up_flash_access();
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to set up flash access\n");
- return retval;
- }
- app_info = &tcm_hcd->app_info;
- boot_info = &tcm_hcd->boot_info;
- switch (area) {
- case BOOT_CONFIG:
- temp = le2_to_uint(boot_info->boot_config_start_block);
- addr = temp * reflash_hcd->write_block_size;
- length = BOOT_CONFIG_SIZE * BOOT_CONFIG_SLOTS;
- break;
- case APP_CONFIG:
- temp = le2_to_uint(app_info->app_config_start_write_block);
- addr = temp * reflash_hcd->write_block_size;
- length = le2_to_uint(app_info->app_config_size);
- break;
- case DISP_CONFIG:
- temp = le4_to_uint(boot_info->display_config_start_block);
- addr = temp * reflash_hcd->write_block_size;
- temp = le2_to_uint(boot_info->display_config_length_blocks);
- length = temp * reflash_hcd->write_block_size;
- break;
- case CUSTOM_OTP:
- temp = le2_to_uint(boot_info->custom_otp_start_block);
- addr = temp * reflash_hcd->write_block_size;
- temp = le2_to_uint(boot_info->custom_otp_length_blocks);
- length = temp * reflash_hcd->write_block_size;
- break;
- case CUSTOM_LCM:
- case CUSTOM_OEM:
- case PPDT:
- addr *= reflash_hcd->write_block_size;
- length *= reflash_hcd->write_block_size;
- break;
- default:
- LOGE(tcm_hcd->pdev->dev.parent,
- "Invalid data area\n");
- retval = -EINVAL;
- goto run_app_firmware;
- }
- if (addr == 0 || length == 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Data area unavailable\n");
- retval = -EINVAL;
- goto run_app_firmware;
- }
- LOCK_BUFFER(reflash_hcd->read);
- retval = syna_tcm_alloc_mem(tcm_hcd,
- &reflash_hcd->read,
- length);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to allocate memory for read.buf\n");
- UNLOCK_BUFFER(reflash_hcd->read);
- goto run_app_firmware;
- }
- retval = reflash_read_flash(addr, reflash_hcd->read.buf, length);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to read from flash\n");
- UNLOCK_BUFFER(reflash_hcd->read);
- goto run_app_firmware;
- }
- reflash_hcd->read.data_length = length;
- if (output != NULL) {
- retval = syna_tcm_alloc_mem(tcm_hcd,
- output,
- length);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to allocate memory for output->buf\n");
- UNLOCK_BUFFER(reflash_hcd->read);
- goto run_app_firmware;
- }
- retval = secure_memcpy(output->buf,
- output->buf_size,
- reflash_hcd->read.buf,
- reflash_hcd->read.buf_size,
- length);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to copy read data\n");
- UNLOCK_BUFFER(reflash_hcd->read);
- goto run_app_firmware;
- }
- output->data_length = length;
- }
- UNLOCK_BUFFER(reflash_hcd->read);
- retval = 0;
- run_app_firmware:
- if (!run_app_firmware)
- goto exit;
- if (tcm_hcd->switch_mode(tcm_hcd, FW_MODE_APPLICATION) < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to run application firmware\n");
- }
- exit:
- return retval;
- }
- static int reflash_check_boot_config(void)
- {
- unsigned int temp;
- unsigned int image_addr;
- unsigned int device_addr;
- struct syna_tcm_hcd *tcm_hcd = reflash_hcd->tcm_hcd;
- if (reflash_hcd->image_info.boot_config.size < BOOT_CONFIG_SIZE) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "No valid boot config in image file\n");
- return -EINVAL;
- }
- image_addr = reflash_hcd->image_info.boot_config.flash_addr;
- temp = le2_to_uint(tcm_hcd->boot_info.boot_config_start_block);
- device_addr = temp * reflash_hcd->write_block_size;
- if (image_addr != device_addr) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Flash address mismatch\n");
- return -EINVAL;
- }
- return 0;
- }
- static int reflash_check_app_config(void)
- {
- unsigned int temp;
- unsigned int image_addr;
- unsigned int image_size;
- unsigned int device_addr;
- unsigned int device_size;
- struct syna_tcm_hcd *tcm_hcd = reflash_hcd->tcm_hcd;
- if (reflash_hcd->image_info.app_config.size == 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "No application config in image file\n");
- return -EINVAL;
- }
- image_addr = reflash_hcd->image_info.app_config.flash_addr;
- image_size = reflash_hcd->image_info.app_config.size;
- temp = le2_to_uint(tcm_hcd->app_info.app_config_start_write_block);
- device_addr = temp * reflash_hcd->write_block_size;
- device_size = le2_to_uint(tcm_hcd->app_info.app_config_size);
- if (device_addr == 0 && device_size == 0)
- return 0;
- if (image_addr != device_addr) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Flash address mismatch\n");
- return -EINVAL;
- }
- if (image_size != device_size) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Config size mismatch\n");
- return -EINVAL;
- }
- return 0;
- }
- static int reflash_check_disp_config(void)
- {
- unsigned int temp;
- unsigned int image_addr;
- unsigned int image_size;
- unsigned int device_addr;
- unsigned int device_size;
- struct syna_tcm_hcd *tcm_hcd = reflash_hcd->tcm_hcd;
- if (reflash_hcd->image_info.disp_config.size == 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "No display config in image file\n");
- return -EINVAL;
- }
- image_addr = reflash_hcd->image_info.disp_config.flash_addr;
- image_size = reflash_hcd->image_info.disp_config.size;
- temp = le4_to_uint(tcm_hcd->boot_info.display_config_start_block);
- device_addr = temp * reflash_hcd->write_block_size;
- temp = le2_to_uint(tcm_hcd->boot_info.display_config_length_blocks);
- device_size = temp * reflash_hcd->write_block_size;
- if (image_addr != device_addr) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Flash address mismatch\n");
- return -EINVAL;
- }
- if (image_size != device_size) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Config size mismatch\n");
- return -EINVAL;
- }
- return 0;
- }
- static int reflash_check_prod_test_firmware(void)
- {
- struct syna_tcm_hcd *tcm_hcd = reflash_hcd->tcm_hcd;
- if (reflash_hcd->image_info.prod_test_firmware.size == 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "No production test firmware in image file\n");
- return -EINVAL;
- }
- return 0;
- }
- static int reflash_check_app_firmware(void)
- {
- struct syna_tcm_hcd *tcm_hcd = reflash_hcd->tcm_hcd;
- if (reflash_hcd->image_info.app_firmware.size == 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "No application firmware in image file\n");
- return -EINVAL;
- }
- return 0;
- }
- static int reflash_write_flash(unsigned int address, const unsigned char *data,
- unsigned int datalen)
- {
- int retval;
- unsigned int offset;
- unsigned int w_length;
- unsigned int xfer_length;
- unsigned int remaining_length;
- unsigned int flash_address;
- unsigned int block_address;
- struct syna_tcm_hcd *tcm_hcd = reflash_hcd->tcm_hcd;
- w_length = tcm_hcd->wr_chunk_size - 5;
- w_length = w_length - (w_length % reflash_hcd->write_block_size);
- w_length = MIN(w_length, reflash_hcd->max_write_payload_size);
- offset = 0;
- remaining_length = datalen;
- LOCK_BUFFER(reflash_hcd->out);
- LOCK_BUFFER(reflash_hcd->resp);
- while (remaining_length) {
- if (remaining_length > w_length)
- xfer_length = w_length;
- else
- xfer_length = remaining_length;
- retval = syna_tcm_alloc_mem(tcm_hcd,
- &reflash_hcd->out,
- xfer_length + 2);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to allocate memory for out.buf\n");
- UNLOCK_BUFFER(reflash_hcd->resp);
- UNLOCK_BUFFER(reflash_hcd->out);
- return retval;
- }
- flash_address = address + offset;
- block_address = flash_address / reflash_hcd->write_block_size;
- reflash_hcd->out.buf[0] = (unsigned char)block_address;
- reflash_hcd->out.buf[1] = (unsigned char)(block_address >> 8);
- retval = secure_memcpy(&reflash_hcd->out.buf[2],
- reflash_hcd->out.buf_size - 2,
- &data[offset],
- datalen - offset,
- xfer_length);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to copy write data\n");
- UNLOCK_BUFFER(reflash_hcd->resp);
- UNLOCK_BUFFER(reflash_hcd->out);
- return retval;
- }
- retval = tcm_hcd->write_message(tcm_hcd,
- CMD_WRITE_FLASH,
- reflash_hcd->out.buf,
- xfer_length + 2,
- &reflash_hcd->resp.buf,
- &reflash_hcd->resp.buf_size,
- &reflash_hcd->resp.data_length,
- NULL,
- WRITE_FLASH_DELAY_MS);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to write command %s\n",
- STR(CMD_WRITE_FLASH));
- LOGE(tcm_hcd->pdev->dev.parent,
- "Flash address = 0x%08x\n",
- flash_address);
- LOGE(tcm_hcd->pdev->dev.parent,
- "Data length = %d\n",
- xfer_length);
- UNLOCK_BUFFER(reflash_hcd->resp);
- UNLOCK_BUFFER(reflash_hcd->out);
- return retval;
- }
- offset += xfer_length;
- remaining_length -= xfer_length;
- }
- UNLOCK_BUFFER(reflash_hcd->resp);
- UNLOCK_BUFFER(reflash_hcd->out);
- return 0;
- }
- reflash_write(app_config)
- reflash_write(disp_config)
- reflash_write(prod_test_firmware)
- reflash_write(app_firmware)
- static int reflash_erase_flash(unsigned int page_start, unsigned int page_count)
- {
- int retval;
- unsigned char out_buf[2];
- struct syna_tcm_hcd *tcm_hcd = reflash_hcd->tcm_hcd;
- out_buf[0] = (unsigned char)page_start;
- out_buf[1] = (unsigned char)page_count;
- LOCK_BUFFER(reflash_hcd->resp);
- retval = tcm_hcd->write_message(tcm_hcd,
- CMD_ERASE_FLASH,
- out_buf,
- sizeof(out_buf),
- &reflash_hcd->resp.buf,
- &reflash_hcd->resp.buf_size,
- &reflash_hcd->resp.data_length,
- NULL,
- ERASE_FLASH_DELAY_MS);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to write command %s\n",
- STR(CMD_ERASE_FLASH));
- UNLOCK_BUFFER(reflash_hcd->resp);
- return retval;
- }
- UNLOCK_BUFFER(reflash_hcd->resp);
- return 0;
- }
- reflash_erase(app_config)
- reflash_erase(disp_config)
- reflash_erase(prod_test_firmware)
- reflash_erase(app_firmware)
- static int reflash_update_custom_otp(const unsigned char *data,
- unsigned int offset, unsigned int datalen)
- {
- int retval;
- unsigned int temp;
- unsigned int addr;
- unsigned int length;
- struct syna_tcm_hcd *tcm_hcd = reflash_hcd->tcm_hcd;
- retval = reflash_set_up_flash_access();
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to set up flash access\n");
- return retval;
- }
- tcm_hcd->update_watchdog(tcm_hcd, false);
- temp = le2_to_uint(tcm_hcd->boot_info.custom_otp_start_block);
- addr = temp * reflash_hcd->write_block_size;
- temp = le2_to_uint(tcm_hcd->boot_info.custom_otp_length_blocks);
- length = temp * reflash_hcd->write_block_size;
- if (addr == 0 || length == 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Data area unavailable\n");
- retval = -EINVAL;
- goto run_app_firmware;
- }
- if (datalen + offset > length) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Invalid data length\n");
- retval = -EINVAL;
- goto run_app_firmware;
- }
- retval = reflash_write_flash(addr + offset,
- data,
- datalen);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to write to flash\n");
- goto run_app_firmware;
- }
- retval = 0;
- run_app_firmware:
- if (tcm_hcd->switch_mode(tcm_hcd, FW_MODE_APPLICATION) < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to run application firmware\n");
- }
- tcm_hcd->update_watchdog(tcm_hcd, true);
- return retval;
- }
- static int reflash_update_custom_lcm(const unsigned char *data,
- unsigned int offset, unsigned int datalen)
- {
- int retval;
- unsigned int addr;
- unsigned int length;
- unsigned int page_start;
- unsigned int page_count;
- struct syna_tcm_hcd *tcm_hcd = reflash_hcd->tcm_hcd;
- retval = tcm_hcd->get_data_location(tcm_hcd,
- CUSTOM_LCM,
- &addr,
- &length);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to get data location\n");
- return retval;
- }
- retval = reflash_set_up_flash_access();
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to set up flash access\n");
- return retval;
- }
- tcm_hcd->update_watchdog(tcm_hcd, false);
- addr *= reflash_hcd->write_block_size;
- length *= reflash_hcd->write_block_size;
- if (addr == 0 || length == 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Data area unavailable\n");
- retval = -EINVAL;
- goto run_app_firmware;
- }
- if (datalen + offset > length) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Invalid data length\n");
- retval = -EINVAL;
- goto run_app_firmware;
- }
- if (offset == 0) {
- page_start = addr / reflash_hcd->page_size;
- page_count = ceil_div(length, reflash_hcd->page_size);
- retval = reflash_erase_flash(page_start, page_count);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to erase flash pages\n");
- goto run_app_firmware;
- }
- }
- retval = reflash_write_flash(addr + offset,
- data,
- datalen);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to write to flash\n");
- goto run_app_firmware;
- }
- retval = 0;
- run_app_firmware:
- if (tcm_hcd->switch_mode(tcm_hcd, FW_MODE_APPLICATION) < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to run application firmware\n");
- }
- tcm_hcd->update_watchdog(tcm_hcd, true);
- return retval;
- }
- static int reflash_update_custom_oem(const unsigned char *data,
- unsigned int offset, unsigned int datalen)
- {
- int retval;
- unsigned int addr;
- unsigned int length;
- unsigned int page_start;
- unsigned int page_count;
- struct syna_tcm_hcd *tcm_hcd = reflash_hcd->tcm_hcd;
- retval = tcm_hcd->get_data_location(tcm_hcd,
- CUSTOM_OEM,
- &addr,
- &length);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to get data location\n");
- return retval;
- }
- retval = reflash_set_up_flash_access();
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to set up flash access\n");
- return retval;
- }
- tcm_hcd->update_watchdog(tcm_hcd, false);
- addr *= reflash_hcd->write_block_size;
- length *= reflash_hcd->write_block_size;
- if (addr == 0 || length == 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Data area unavailable\n");
- retval = -EINVAL;
- goto run_app_firmware;
- }
- if (datalen + offset > length) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Invalid data length\n");
- retval = -EINVAL;
- goto run_app_firmware;
- }
- if (offset == 0) {
- page_start = addr / reflash_hcd->page_size;
- page_count = ceil_div(length, reflash_hcd->page_size);
- retval = reflash_erase_flash(page_start, page_count);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to erase flash pages\n");
- goto run_app_firmware;
- }
- }
- retval = reflash_write_flash(addr + offset,
- data,
- datalen);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to write to flash\n");
- goto run_app_firmware;
- }
- retval = 0;
- run_app_firmware:
- if (tcm_hcd->switch_mode(tcm_hcd, FW_MODE_APPLICATION) < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to run application firmware\n");
- }
- tcm_hcd->update_watchdog(tcm_hcd, true);
- return retval;
- }
- static int reflash_update_boot_config(bool lock)
- {
- int retval;
- unsigned char slot_used;
- unsigned int idx;
- unsigned int addr = 0;
- struct boot_config *data;
- struct boot_config *last_slot;
- struct syna_tcm_hcd *tcm_hcd = reflash_hcd->tcm_hcd;
- retval = reflash_set_up_flash_access();
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to set up flash access\n");
- return retval;
- }
- tcm_hcd->update_watchdog(tcm_hcd, false);
- retval = reflash_check_boot_config();
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed boot_config partition check\n");
- goto reset;
- }
- retval = reflash_read_data(BOOT_CONFIG, false, NULL);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to read boot config\n");
- goto reset;
- }
- LOCK_BUFFER(reflash_hcd->read);
- data = (struct boot_config *)reflash_hcd->read.buf;
- last_slot = data + (BOOT_CONFIG_SLOTS - 1);
- slot_used = tcm_hcd->id_info.mode == MODE_TDDI_BOOTLOADER ? 0 : 1;
- if (last_slot->used == slot_used) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Boot config already locked down\n");
- UNLOCK_BUFFER(reflash_hcd->read);
- goto reset;
- }
- if (lock) {
- idx = BOOT_CONFIG_SLOTS - 1;
- } else {
- for (idx = 0; idx < BOOT_CONFIG_SLOTS; idx++) {
- if (data->used == slot_used) {
- data++;
- continue;
- } else {
- break;
- }
- }
- }
- UNLOCK_BUFFER(reflash_hcd->read);
- if (idx == BOOT_CONFIG_SLOTS) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "No free boot config slot available\n");
- goto reset;
- }
- addr += idx * BOOT_CONFIG_SIZE;
- retval = reflash_write_flash(addr,
- reflash_hcd->image_info.boot_config.data,
- BOOT_CONFIG_SIZE);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to write to flash\n");
- goto reset;
- }
- LOGN(tcm_hcd->pdev->dev.parent,
- "Slot %d updated with new boot config\n",
- idx);
- retval = 0;
- reset:
- if (tcm_hcd->reset(tcm_hcd, false, true) < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to do reset\n");
- }
- tcm_hcd->update_watchdog(tcm_hcd, true);
- return retval;
- }
- reflash_update(app_config)
- reflash_update(disp_config)
- reflash_update(prod_test_firmware)
- reflash_update(app_firmware)
- static int reflash_do_reflash(void)
- {
- int retval;
- enum update_area update_area;
- struct syna_tcm_hcd *tcm_hcd = reflash_hcd->tcm_hcd;
- retval = reflash_get_fw_image();
- if (retval < 0) {
- LOGD(tcm_hcd->pdev->dev.parent,
- "Failed to get firmware image\n");
- goto exit;
- }
- LOGD(tcm_hcd->pdev->dev.parent,
- "Start of reflash\n");
- atomic_set(&tcm_hcd->firmware_flashing, 1);
- update_area = reflash_compare_id_info();
- switch (update_area) {
- case FIRMWARE_CONFIG:
- retval = reflash_update_app_firmware(false);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to reflash application firmware\n");
- goto exit;
- }
- memset(&tcm_hcd->app_info, 0x00, sizeof(tcm_hcd->app_info));
- if (tcm_hcd->features.dual_firmware) {
- retval = reflash_update_prod_test_firmware(false);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to reflash production test\n");
- goto exit;
- }
- }
- case CONFIG_ONLY:
- if (reflash_hcd->disp_cfg_update) {
- retval = reflash_update_disp_config(false);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to reflash display config\n");
- goto exit;
- }
- }
- retval = reflash_update_app_config(true);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to reflash application config\n");
- goto exit;
- }
- break;
- case NONE:
- default:
- break;
- }
- LOGD(tcm_hcd->pdev->dev.parent,
- "End of reflash\n");
- retval = 0;
- exit:
- if (reflash_hcd->fw_entry) {
- release_firmware(reflash_hcd->fw_entry);
- reflash_hcd->fw_entry = NULL;
- reflash_hcd->image = NULL;
- reflash_hcd->image_size = 0;
- }
- atomic_set(&tcm_hcd->firmware_flashing, 0);
- wake_up_interruptible(&tcm_hcd->reflash_wq);
- return retval;
- }
- #ifdef STARTUP_REFLASH
- static void reflash_startup_work(struct work_struct *work)
- {
- int retval;
- #if defined(CONFIG_DRM) || defined(CONFIG_FB)
- unsigned int timeout;
- #endif
- struct syna_tcm_hcd *tcm_hcd = reflash_hcd->tcm_hcd;
- #if defined(CONFIG_DRM) || defined(CONFIG_FB)
- timeout = FB_READY_TIMEOUT_S * 1000 / FB_READY_WAIT_MS;
- while (tcm_hcd->fb_ready != FB_READY_COUNT - 1) {
- if (timeout == 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Timed out waiting for FB ready\n");
- return;
- }
- msleep(FB_READY_WAIT_MS);
- timeout--;
- }
- #endif
- pm_stay_awake(&tcm_hcd->pdev->dev);
- mutex_lock(&reflash_hcd->reflash_mutex);
- retval = reflash_do_reflash();
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to do reflash\n");
- }
- mutex_unlock(&reflash_hcd->reflash_mutex);
- pm_relax(&tcm_hcd->pdev->dev);
- }
- #endif
- static int reflash_init(struct syna_tcm_hcd *tcm_hcd)
- {
- int retval = 0;
- int idx;
- reflash_hcd = kzalloc(sizeof(*reflash_hcd), GFP_KERNEL);
- if (!reflash_hcd) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to allocate memory for reflash_hcd\n");
- return -ENOMEM;
- }
- reflash_hcd->image_buf = kzalloc(IMAGE_BUF_SIZE, GFP_KERNEL);
- if (!reflash_hcd->image_buf) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to allocate memory for image_buf\n");
- goto err_allocate_memory;
- }
- reflash_hcd->tcm_hcd = tcm_hcd;
- reflash_hcd->force_update = FORCE_REFLASH;
- mutex_init(&reflash_hcd->reflash_mutex);
- INIT_BUFFER(reflash_hcd->out, false);
- INIT_BUFFER(reflash_hcd->resp, false);
- INIT_BUFFER(reflash_hcd->read, false);
- #ifdef STARTUP_REFLASH
- reflash_hcd->workqueue =
- create_singlethread_workqueue("syna_tcm_reflash");
- INIT_WORK(&reflash_hcd->work, reflash_startup_work);
- queue_work(reflash_hcd->workqueue, &reflash_hcd->work);
- #endif
- if (!ENABLE_SYSFS_INTERFACE)
- return 0;
- reflash_hcd->sysfs_dir = kobject_create_and_add(SYSFS_DIR_NAME,
- tcm_hcd->sysfs_dir);
- if (!reflash_hcd->sysfs_dir) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to create sysfs directory\n");
- retval = -EINVAL;
- goto err_sysfs_create_dir;
- }
- for (idx = 0; idx < ARRAY_SIZE(attrs); idx++) {
- retval = sysfs_create_file(reflash_hcd->sysfs_dir,
- &(*attrs[idx]).attr);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to create sysfs file\n");
- goto err_sysfs_create_file;
- }
- }
- retval = sysfs_create_bin_file(reflash_hcd->sysfs_dir, &bin_attrs[0]);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to create sysfs bin file\n");
- goto err_sysfs_create_bin_file;
- }
- reflash_hcd->custom_dir = kobject_create_and_add(CUSTOM_DIR_NAME,
- reflash_hcd->sysfs_dir);
- if (!reflash_hcd->custom_dir) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to create custom sysfs directory\n");
- retval = -EINVAL;
- goto err_custom_sysfs_create_dir;
- }
- for (idx = 1; idx < ARRAY_SIZE(bin_attrs); idx++) {
- retval = sysfs_create_bin_file(reflash_hcd->custom_dir,
- &bin_attrs[idx]);
- if (retval < 0) {
- LOGE(tcm_hcd->pdev->dev.parent,
- "Failed to create sysfs bin file\n");
- goto err_custom_sysfs_create_bin_file;
- }
- }
- tcm_hcd->read_flash_data = reflash_read_data;
- return 0;
- err_custom_sysfs_create_bin_file:
- for (idx--; idx > 0; idx--)
- sysfs_remove_bin_file(reflash_hcd->custom_dir, &bin_attrs[idx]);
- kobject_put(reflash_hcd->custom_dir);
- idx = ARRAY_SIZE(attrs);
- err_custom_sysfs_create_dir:
- sysfs_remove_bin_file(reflash_hcd->sysfs_dir, &bin_attrs[0]);
- err_sysfs_create_bin_file:
- err_sysfs_create_file:
- for (idx--; idx >= 0; idx--)
- sysfs_remove_file(reflash_hcd->sysfs_dir, &(*attrs[idx]).attr);
- kobject_put(reflash_hcd->sysfs_dir);
- err_sysfs_create_dir:
- err_allocate_memory:
- kfree(reflash_hcd->image_buf);
- RELEASE_BUFFER(reflash_hcd->read);
- RELEASE_BUFFER(reflash_hcd->resp);
- RELEASE_BUFFER(reflash_hcd->out);
- kfree(reflash_hcd);
- reflash_hcd = NULL;
- return retval;
- }
- static int reflash_remove(struct syna_tcm_hcd *tcm_hcd)
- {
- int idx;
- if (!reflash_hcd)
- goto exit;
- tcm_hcd->read_flash_data = NULL;
- if (ENABLE_SYSFS_INTERFACE) {
- for (idx = 1; idx < ARRAY_SIZE(bin_attrs); idx++) {
- sysfs_remove_bin_file(reflash_hcd->custom_dir,
- &bin_attrs[idx]);
- }
- kobject_put(reflash_hcd->custom_dir);
- sysfs_remove_bin_file(reflash_hcd->sysfs_dir, &bin_attrs[0]);
- for (idx = 0; idx < ARRAY_SIZE(attrs); idx++) {
- sysfs_remove_file(reflash_hcd->sysfs_dir,
- &(*attrs[idx]).attr);
- }
- kobject_put(reflash_hcd->sysfs_dir);
- }
- #ifdef STARTUP_REFLASH
- cancel_work_sync(&reflash_hcd->work);
- flush_workqueue(reflash_hcd->workqueue);
- destroy_workqueue(reflash_hcd->workqueue);
- #endif
- kfree(reflash_hcd->image_buf);
- RELEASE_BUFFER(reflash_hcd->read);
- RELEASE_BUFFER(reflash_hcd->resp);
- RELEASE_BUFFER(reflash_hcd->out);
- kfree(reflash_hcd);
- reflash_hcd = NULL;
- exit:
- complete(&reflash_remove_complete);
- return 0;
- }
- static int reflash_reset(struct syna_tcm_hcd *tcm_hcd)
- {
- int retval;
- if (!reflash_hcd) {
- retval = reflash_init(tcm_hcd);
- return retval;
- }
- return 0;
- }
- static struct syna_tcm_module_cb reflash_module = {
- .type = TCM_REFLASH,
- .init = reflash_init,
- .remove = reflash_remove,
- .syncbox = NULL,
- .asyncbox = NULL,
- .reset = reflash_reset,
- .suspend = NULL,
- .resume = NULL,
- .early_suspend = NULL,
- };
- static int __init reflash_module_init(void)
- {
- return syna_tcm_add_module(&reflash_module, true);
- }
- static void __exit reflash_module_exit(void)
- {
- syna_tcm_add_module(&reflash_module, false);
- wait_for_completion(&reflash_remove_complete);
- }
- module_init(reflash_module_init);
- module_exit(reflash_module_exit);
- MODULE_AUTHOR("Synaptics, Inc.");
- MODULE_DESCRIPTION("Synaptics TCM Reflash Module");
- MODULE_LICENSE("GPL v2");
|