static ssize_t qfprom_write_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int ret = 0; if (!enable) { printk("%s: qfprom write is not enabled\n", __func__); return -EINVAL; } if (!qfprom_address) { printk("%s: qfprom address is NULL\n", __func__); return -EINVAL; } ret = qfuse_write_single_row(qfprom_address, qfprom_lsb_value, qfprom_msb_value); qfprom_address = 0; if (ret == 0) return count; else if (ret < 0) printk("%s: scm call fail error = %d\n", __func__, ret); else printk("%s: qfprom write status error = %d\n", __func__, ret); return -EINVAL; }
static ssize_t qfprom_sdp_enum_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count) { int cmd; int ret; struct qfprom_blow_data sdp_data = { QFPROM_DEBUG_DISABLE, 0x200, 0x0 }; if (sscanf(buf, "%d", &cmd) != 1) return -EINVAL; if (cmd) { ret = qfuse_write_single_row(sdp_data.qfprom_addr,sdp_data.lsb_data,sdp_data.msb_data); if(ret!=0){ printk("%s: qfuse addr %x blow write error!!!\n",__func__,sdp_data.qfprom_addr); return -EINVAL; } } return count; }
int qfprom_blow_secondary_hwkey_region(void) { int ret; u32 addr, lsb, msb; int i; u32 *p_buf = NULL; p_buf = kmalloc(sizeof(u32)*2, GFP_KERNEL); if(!p_buf){ printk("%s : buffer memory alloc fail\n", __func__); return -ENOMEM; } /* we check read permission * if read permission region is blown, we can see all hw secondary key is blown * because permission fuse is follow to secondary hw key */ ret = qfuse_read_single_row(QFPROM_RD_WR_PERMISSION, 0, p_buf); if(ret != 0){ printk("%s: qfuse addr %x read fail, ret=%d\n", __func__, QFPROM_RD_WR_PERMISSION, ret); ret = -EINVAL; goto err; } if((p_buf[0]&0x0C000000) == 0x0C000000) { printk("%s: All hw key was written already\n", __func__); ret = 0; goto err; } addr = QFPROM_SECONDARY_HW_KEY; for(i=0;i<7;i++){ /* we can read hw secondary key region because before read permission is set */ /* ret = qfuse_read_single_row(addr, 0, p_buf); if(ret != 0){ printk("%s: qfuse addr %x read fail, ret=%d\n", __func__, addr,ret); ret = -EINVAL; goto err; } printk("%s:Currently, secondary key addr=0x%x, lsb=0x%x, msb=0x%x\n", __func__, addr,p_buf[0], p_buf[1]); */ msleep(10); /* if you have not written ever hw key before, value to read will be zero * so create random using tzbsp * LSB region */ if(!p_buf[0]){ lsb = qfprom_create_random(); if(!lsb) { ret = -EINVAL; goto err; } msleep(5); } else { /* dont create random value and rewrite value to read */ printk("hw lsb key was blow already in 0x%x addr\n", addr); lsb = p_buf[0]; } /* if you have not written ever hw key before, value to read will be zero * so create random using tzbsp * MSB region */ if(!p_buf[1]) { msb = qfprom_create_random(); if(!msb) { ret = -EINVAL; goto err; } msleep(5); } else { printk("hw msb key was blow already in 0x%x addr\n", addr+4); msb = p_buf[1]; } /* must mask FEC bit */ lsb = lsb&HW_KEY_LSB_FEC_MASK; msb = msb&HW_KEY_MSB_FEC_MASK; printk("We start to writing secondary key !!!\n"); printk("addr=0x%x, lsb=0x%x, msb=0x%x\n", addr, lsb, msb); msleep(10); ret = qfuse_write_single_row(addr, lsb, msb); if(ret != 0) { printk("%s:qfus addr 0x%x write error, ret=%d\n", __func__, addr, ret); ret = -EINVAL; goto err; } else { /* write double check routine */ printk("hw secondary key write successful\n"); msleep(10); /* ret = qfuse_read_single_row(addr, 0, p_buf); if(ret != 0) { printk("%s:read fail when double check routine, ret=%d\n", __func__, ret); goto err; } if((p_buf[0]==lsb)&&(p_buf[1]==msb)) printk("%s: hw key write double check successful!!!!!!!\n",__func__); else { printk("%s: hw key double check error, read_lsb=0x%x,read_msb=0x%x\n",__func__,p_buf[0],p_buf[1]); ret = -EINVAL; goto err; } */ } addr = addr+8; msleep(10); } err: kfree(p_buf); return ret; }
/* this api handle diag command(fusing command) from ATD * this api fuse secure boot, jtag disable, oem config, secondary hw key, R/W permission * this api check secondary hw key status before fusing R/W permission */ static ssize_t qfusing_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int ret; int i = 0; u32 *p_buf = NULL; u32 fusing_flag=0; if(!sysfs_streq(buf, "fusing")){ printk("%s:argument fault\n", __func__); ret = -EINVAL; goto err; } p_buf = kmalloc(sizeof(u32)*2, GFP_KERNEL); if(!p_buf) { printk("%s: memory alloc fail\n", __func__); ret = -EINVAL; goto err;; } for(i=0;i<ARRAY_SIZE(blow_data);i++){ if(blow_data[i].qfprom_addr==QFPROM_CHECK_HW_KEY) { /* We dont check secondary hw key status * But qfprom_blow secondary_hwkey_region api does not create random if qfprom block was written * The api create random if was not written only * So HW key region to be written is not written by new random key * The reason to not check hw key status reg is to check 7 hw key block to be written */ ret = qfprom_blow_secondary_hwkey_region(); if(ret < 0) { printk("%s: hw key region blow error\n", __func__); goto err_fuse; } fusing_flag |= (0x1<<i); printk("%s: HW secondary key region is blown successfully\n", __func__); continue; } msleep(10); ret = qfuse_read_single_row(blow_data[i].qfprom_addr, 0, p_buf); if(ret != 0) { printk("%s: qfprom addr %x read fail, ret=%d\n", __func__, blow_data[i].qfprom_addr, ret); goto err_fuse; } printk("%s:read addr 0x%x, lsb 0x%x, msb 0x%x\n", __func__, blow_data[i].qfprom_addr, p_buf[0], p_buf[1]); /* Don't rewrite if value to read is same value to write */ if(((p_buf[0]&blow_data[i].lsb_data) == blow_data[i].lsb_data) && ((p_buf[1]&blow_data[i].msb_data) == blow_data[i].msb_data)) { printk("%s: 0x%x was blown already\n", __func__, blow_data[i].qfprom_addr); } else { msleep(10); ret = qfuse_write_single_row(blow_data[i].qfprom_addr, blow_data[i].lsb_data, blow_data[i].msb_data); if(ret != 0) { printk("%s: qfuse addr %x blow write error!!!\n", __func__, blow_data[i].qfprom_addr); ret = -EINVAL; goto err_fuse; } else { /* double check routine*/ msleep(10); printk("%s: qfprom 0x%x addr write double check routine\n", __func__, blow_data[i].qfprom_addr); ret = qfuse_read_single_row(blow_data[i].qfprom_addr, 0, p_buf); if(ret != 0) { printk("%s: read fail when double check, ret=%d\n", __func__, ret); ret = -EINVAL; goto err_fuse; } if(((p_buf[0]&blow_data[i].lsb_data) == blow_data[i].lsb_data) && ((p_buf[1]&blow_data[i].msb_data) == blow_data[i].msb_data)) { printk("%s:write double check successfully", __func__); } else { printk("%s:qfprom write successful but error when double check\n", __func__); ret = -EINVAL; goto err_fuse; } } } fusing_flag |= (0x1<<i); } printk("%s: fusing flag = 0x%x\n", __func__, fusing_flag); printk("%s: fusing complete!!!!!!!!!!!!!!!!!!!!\n", __func__); kfree(p_buf); return count; err_fuse: kfree(p_buf); err: return ret; }