Loading drivers/soc/qcom/dcc_v2.c +200 −84 Original line number Diff line number Diff line Loading @@ -74,6 +74,9 @@ #define DCC_RD_MOD_WR_DESCRIPTOR (BIT(31)) #define DCC_LINK_DESCRIPTOR (BIT(31) | BIT(30)) #define DCC_READ_IND 0x00 #define DCC_WRITE_IND (BIT(28)) #define DCC_MAX_LINK_LIST 5 #define DCC_INVALID_LINK_LIST 0xFF Loading @@ -92,6 +95,13 @@ enum dcc_data_sink { DCC_DATA_SINK_ATB }; enum dcc_descriptor_type { DCC_ADDR_TYPE, DCC_LOOP_TYPE, DCC_READ_WRITE_TYPE, DCC_WRITE_TYPE }; static const char * const str_dcc_data_sink[] = { [DCC_DATA_SINK_SRAM] = "sram", [DCC_DATA_SINK_ATB] = "atb", Loading @@ -108,9 +118,9 @@ struct dcc_config_entry { uint32_t len; uint32_t index; uint32_t loop_cnt; uint32_t rd_mod_wr; uint32_t write_val; uint32_t mask; bool rd_wr_entry; enum dcc_descriptor_type desc_type; struct list_head list; }; Loading Loading @@ -189,7 +199,7 @@ static int dcc_sw_trigger(struct dcc_drvdata *drvdata) mutex_lock(&drvdata->mutex); if (!dcc_ready(drvdata)) { dev_err(drvdata->dev, "DCC is not ready!\n"); dev_err(drvdata->dev, "DCC is not ready\n"); ret = -EBUSY; goto err; } Loading Loading @@ -224,7 +234,7 @@ static int __dcc_ll_cfg(struct dcc_drvdata *drvdata, int curr_list) uint32_t loop_off = 0; uint32_t link; uint32_t pos, total_len = 0, loop_len = 0; uint32_t loop, loop_cnt; uint32_t loop, loop_cnt = 0; bool loop_start = false; struct dcc_config_entry *entry; Loading @@ -233,7 +243,9 @@ static int __dcc_ll_cfg(struct dcc_drvdata *drvdata, int curr_list) link = 0; list_for_each_entry(entry, &drvdata->cfg_head[curr_list], list) { if (entry->rd_wr_entry) { switch (entry->desc_type) { case DCC_READ_WRITE_TYPE: { if (link) { /* write new offset = 1 to continue * processing the list Loading @@ -255,12 +267,14 @@ static int __dcc_ll_cfg(struct dcc_drvdata *drvdata, int curr_list) dcc_sram_writel(drvdata, entry->mask, sram_offset); sram_offset += 4; dcc_sram_writel(drvdata, entry->rd_mod_wr, sram_offset); dcc_sram_writel(drvdata, entry->write_val, sram_offset); sram_offset += 4; continue; addr = 0; break; } if (entry->loop_cnt) { case DCC_LOOP_TYPE: { /* Check if we need to write link of prev entry */ if (link) { dcc_sram_writel(drvdata, link, sram_offset); Loading Loading @@ -292,23 +306,66 @@ static int __dcc_ll_cfg(struct dcc_drvdata *drvdata, int curr_list) prev_off = 0; prev_addr = addr; continue; break; } case DCC_WRITE_TYPE: { if (link) { /* write new offset = 1 to continue * processing the list */ link |= ((0x1 << 8) & BM(8, 14)); dcc_sram_writel(drvdata, link, sram_offset); sram_offset += 4; /* Reset link and prev_off */ addr = 0x00; prev_off = 0; prev_addr = addr; } off = entry->offset/4; /* write new offset-length pair to correct position */ link |= ((off & BM(0, 7)) | BIT(15) | ((entry->len << 8) & BM(8, 14))); link |= DCC_LINK_DESCRIPTOR; /* Address type */ addr = (entry->base >> 4) & BM(0, 27); addr |= DCC_ADDR_DESCRIPTOR; addr |= DCC_ADDR_DESCRIPTOR | DCC_WRITE_IND; dcc_sram_writel(drvdata, addr, sram_offset); sram_offset += 4; dcc_sram_writel(drvdata, link, sram_offset); sram_offset += 4; dcc_sram_writel(drvdata, entry->write_val, sram_offset); sram_offset += 4; addr = 0x00; link = 0; break; } default: { /* Address type */ addr = (entry->base >> 4) & BM(0, 27); addr |= DCC_ADDR_DESCRIPTOR | DCC_READ_IND; off = entry->offset/4; total_len += entry->len * 4; if (!prev_addr || prev_addr != addr || prev_off > off) { /* Check if we need to write link of prev entry */ /* Check if we need to write prev link entry */ if (link) { dcc_sram_writel(drvdata, link, sram_offset); dcc_sram_writel(drvdata, link, sram_offset); sram_offset += 4; } dev_err(drvdata->dev, "DCC: sram address.%d\n", sram_offset); dev_dbg(drvdata->dev, "DCC: sram address 0x%x\n", sram_offset); /* Write address */ dcc_sram_writel(drvdata, addr, sram_offset); Loading @@ -319,9 +376,10 @@ static int __dcc_ll_cfg(struct dcc_drvdata *drvdata, int curr_list) prev_off = 0; } if ((off - prev_off) > 0xFF || entry->len > MAX_DCC_LEN) { if ((off - prev_off) > 0xFF || entry->len > MAX_DCC_LEN) { dev_err(drvdata->dev, "DCC: Progamming error! Base: 0x%x, offset 0x%x.\n", "DCC: Progamming error Base: 0x%x, offset 0x%x\n", entry->base, entry->offset); ret = -EINVAL; goto err; Loading @@ -330,7 +388,8 @@ static int __dcc_ll_cfg(struct dcc_drvdata *drvdata, int curr_list) if (link) { /* * link already has one offset-length so new * offset-length needs to be placed at bits [29:15] * offset-length needs to be placed at * bits [29:15] */ pos = 15; Loading @@ -338,8 +397,8 @@ static int __dcc_ll_cfg(struct dcc_drvdata *drvdata, int curr_list) link &= BM(0, 14); } else { /* * link is empty, so new offset-length needs to be * placed at bits [15:0] * link is empty, so new offset-length needs * to be placed at bits [15:0] */ pos = 0; link = 1 << 15; Loading @@ -360,6 +419,8 @@ static int __dcc_ll_cfg(struct dcc_drvdata *drvdata, int curr_list) prev_off = off; prev_addr = addr; } } } if (link) { dcc_sram_writel(drvdata, link, sram_offset); Loading @@ -368,7 +429,7 @@ static int __dcc_ll_cfg(struct dcc_drvdata *drvdata, int curr_list) if (loop_start) { dev_err(drvdata->dev, "DCC: Progamming error! Loop unterminated.\n"); "DCC: Progamming error: Loop unterminated\n"); ret = -EINVAL; goto err; } Loading Loading @@ -457,7 +518,7 @@ static void __dcc_first_crc(struct dcc_drvdata *drvdata) */ for (i = 0; i < 2; i++) { if (!dcc_ready(drvdata)) dev_err(drvdata->dev, "DCC is not ready!\n"); dev_err(drvdata->dev, "DCC is not ready\n"); dcc_writel(drvdata, 1, DCC_LL_SW_TRIGGER(drvdata->curr_list)); Loading @@ -476,13 +537,13 @@ static int dcc_valid_list(struct dcc_drvdata *drvdata, int curr_list) return -EINVAL; if (drvdata->enable[curr_list]) { dev_err(drvdata->dev, "DCC is already enabled!\n"); dev_err(drvdata->dev, "DCC is already enabled\n"); return -EINVAL; } lock_reg = dcc_readl(drvdata, DCC_LL_LOCK(curr_list)); if (lock_reg & 0x1) { dev_err(drvdata->dev, "DCC is already enabled!\n"); dev_err(drvdata->dev, "DCC is already enabled\n"); return -EINVAL; } Loading Loading @@ -565,7 +626,7 @@ static void dcc_disable(struct dcc_drvdata *drvdata) mutex_lock(&drvdata->mutex); if (!dcc_ready(drvdata)) dev_err(drvdata->dev, "DCC is not ready! Disabling DCC...\n"); dev_err(drvdata->dev, "DCC is not ready Disabling DCC...\n"); for (curr_list = 0; curr_list < DCC_MAX_LINK_LIST; curr_list++) { if (!drvdata->enable[curr_list]) Loading Loading @@ -600,7 +661,7 @@ static ssize_t dcc_curr_list(struct device *dev, mutex_lock(&drvdata->mutex); lock_reg = dcc_readl(drvdata, DCC_LL_LOCK(val)); if (lock_reg & 0x1) { dev_err(drvdata->dev, "DCC linked list is already configured!\n"); dev_err(drvdata->dev, "DCC linked list is already configured\n"); mutex_unlock(&drvdata->mutex); return -EINVAL; } Loading Loading @@ -783,25 +844,34 @@ static ssize_t dcc_show_config(struct device *dev, mutex_lock(&drvdata->mutex); list_for_each_entry(entry, &drvdata->cfg_head[drvdata->curr_list], list) { if (entry->rd_wr_entry) switch (entry->desc_type) { case DCC_READ_WRITE_TYPE: len = snprintf(local_buf, 64, "Index: 0x%x, mask: 0x%x, val: 0x%x\n", entry->index, entry->mask, entry->rd_mod_wr); else if (entry->loop_cnt) entry->write_val); break; case DCC_LOOP_TYPE: len = snprintf(local_buf, 64, "Index: 0x%x, Loop: %d\n", entry->index, entry->loop_cnt); else break; case DCC_WRITE_TYPE: len = snprintf(local_buf, 64, "Index: 0x%x, Base: 0x%x, Offset: 0x%x, len: 0x%x\n", "Write Index: 0x%x, Base: 0x%x, Offset: 0x%x, len: 0x%x\n", entry->index, entry->base, entry->offset, entry->len); break; default: len = snprintf(local_buf, 64, "Read Index: 0x%x, Base: 0x%x, Offset: 0x%x, len: 0x%x\n", entry->index, entry->base, entry->offset, entry->len); } if ((count + len) > PAGE_SIZE) { dev_err(dev, "DCC: Couldn't write complete config!\n"); dev_err(dev, "DCC: Couldn't write complete config\n"); break; } strlcat(buf, local_buf, PAGE_SIZE); count += len; } Loading @@ -821,7 +891,7 @@ static int dcc_config_add(struct dcc_drvdata *drvdata, unsigned int addr, mutex_lock(&drvdata->mutex); if (!len) { dev_err(drvdata->dev, "DCC: Invalid length!\n"); dev_err(drvdata->dev, "DCC: Invalid length\n"); ret = -EINVAL; goto err; } Loading Loading @@ -883,6 +953,7 @@ static int dcc_config_add(struct dcc_drvdata *drvdata, unsigned int addr, entry->offset = offset; entry->len = min_t(uint32_t, len, MAX_DCC_LEN); entry->index = drvdata->nr_config[drvdata->curr_list]++; entry->desc_type = DCC_ADDR_TYPE; INIT_LIST_HEAD(&entry->list); list_add_tail(&entry->list, &drvdata->cfg_head[drvdata->curr_list]); Loading Loading @@ -1087,7 +1158,7 @@ static ssize_t dcc_rd_mod_wr(struct device *dev, } if (list_empty(&drvdata->cfg_head[drvdata->curr_list])) { dev_err(drvdata->dev, "DCC: No read address programmed!\n"); dev_err(drvdata->dev, "DCC: No read address programmed\n"); ret = -EPERM; goto err; } Loading @@ -1098,9 +1169,9 @@ static ssize_t dcc_rd_mod_wr(struct device *dev, goto err; } entry->rd_wr_entry = true; entry->desc_type = DCC_READ_WRITE_TYPE; entry->mask = mask; entry->rd_mod_wr = val; entry->write_val = val; entry->index = drvdata->nr_config[drvdata->curr_list]++; INIT_LIST_HEAD(&entry->list); list_add_tail(&entry->list, &drvdata->cfg_head[drvdata->curr_list]); Loading @@ -1110,6 +1181,50 @@ static ssize_t dcc_rd_mod_wr(struct device *dev, } static DEVICE_ATTR(rd_mod_wr, 0200, NULL, dcc_rd_mod_wr); static ssize_t dcc_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { int ret = size; int nval; unsigned int addr, write_val; struct dcc_drvdata *drvdata = dev_get_drvdata(dev); struct dcc_config_entry *entry; mutex_lock(&drvdata->mutex); nval = sscanf(buf, "%x %x", &addr, &write_val); if (drvdata->curr_list >= DCC_MAX_LINK_LIST) { dev_err(dev, "Select link list to program using curr_list\n"); return -EINVAL; } if (nval <= 1 || nval > 2) { ret = -EINVAL; goto err; } entry = devm_kzalloc(drvdata->dev, sizeof(*entry), GFP_KERNEL); if (!entry) { ret = -ENOMEM; goto err; } entry->desc_type = DCC_WRITE_TYPE; entry->base = addr & BM(4, 31); entry->offset = addr - entry->base; entry->write_val = write_val; entry->index = drvdata->nr_config[drvdata->curr_list]++; entry->len = 1; INIT_LIST_HEAD(&entry->list); list_add_tail(&entry->list, &drvdata->cfg_head[drvdata->curr_list]); err: mutex_unlock(&drvdata->mutex); return ret; } static DEVICE_ATTR(config_write, 0200, NULL, dcc_write); static const struct device_attribute *dcc_attrs[] = { &dev_attr_func_type, &dev_attr_data_sink, Loading @@ -1123,6 +1238,7 @@ static const struct device_attribute *dcc_attrs[] = { &dev_attr_loop, &dev_attr_rd_mod_wr, &dev_attr_curr_list, &dev_attr_config_write, NULL, }; Loading @@ -1134,7 +1250,7 @@ static int dcc_create_files(struct device *dev, for (i = 0; attrs[i] != NULL; i++) { ret = device_create_file(dev, attrs[i]); if (ret) { dev_err(dev, "DCC: Couldn't create sysfs attribute: %s!\n", dev_err(dev, "DCC: Couldn't create sysfs attribute: %s\n", attrs[i]->attr.name); break; } Loading Loading @@ -1173,7 +1289,7 @@ static ssize_t dcc_sram_read(struct file *file, char __user *data, if (copy_to_user(data, buf, len)) { dev_err(drvdata->dev, "DCC: Couldn't copy all data to user!\n"); "DCC: Couldn't copy all data to user\n"); kfree(buf); return -EFAULT; } Loading Loading @@ -1372,7 +1488,7 @@ static int dcc_probe(struct platform_device *pdev) } if (i == ARRAY_SIZE(str_dcc_data_sink)) { dev_err(dev, "Unknown sink type for DCC! Using '%s' as data sink\n", dev_err(dev, "Unknown sink type for DCC Using '%s' as data sink\n", str_dcc_data_sink[drvdata->data_sink]); } } Loading Loading
drivers/soc/qcom/dcc_v2.c +200 −84 Original line number Diff line number Diff line Loading @@ -74,6 +74,9 @@ #define DCC_RD_MOD_WR_DESCRIPTOR (BIT(31)) #define DCC_LINK_DESCRIPTOR (BIT(31) | BIT(30)) #define DCC_READ_IND 0x00 #define DCC_WRITE_IND (BIT(28)) #define DCC_MAX_LINK_LIST 5 #define DCC_INVALID_LINK_LIST 0xFF Loading @@ -92,6 +95,13 @@ enum dcc_data_sink { DCC_DATA_SINK_ATB }; enum dcc_descriptor_type { DCC_ADDR_TYPE, DCC_LOOP_TYPE, DCC_READ_WRITE_TYPE, DCC_WRITE_TYPE }; static const char * const str_dcc_data_sink[] = { [DCC_DATA_SINK_SRAM] = "sram", [DCC_DATA_SINK_ATB] = "atb", Loading @@ -108,9 +118,9 @@ struct dcc_config_entry { uint32_t len; uint32_t index; uint32_t loop_cnt; uint32_t rd_mod_wr; uint32_t write_val; uint32_t mask; bool rd_wr_entry; enum dcc_descriptor_type desc_type; struct list_head list; }; Loading Loading @@ -189,7 +199,7 @@ static int dcc_sw_trigger(struct dcc_drvdata *drvdata) mutex_lock(&drvdata->mutex); if (!dcc_ready(drvdata)) { dev_err(drvdata->dev, "DCC is not ready!\n"); dev_err(drvdata->dev, "DCC is not ready\n"); ret = -EBUSY; goto err; } Loading Loading @@ -224,7 +234,7 @@ static int __dcc_ll_cfg(struct dcc_drvdata *drvdata, int curr_list) uint32_t loop_off = 0; uint32_t link; uint32_t pos, total_len = 0, loop_len = 0; uint32_t loop, loop_cnt; uint32_t loop, loop_cnt = 0; bool loop_start = false; struct dcc_config_entry *entry; Loading @@ -233,7 +243,9 @@ static int __dcc_ll_cfg(struct dcc_drvdata *drvdata, int curr_list) link = 0; list_for_each_entry(entry, &drvdata->cfg_head[curr_list], list) { if (entry->rd_wr_entry) { switch (entry->desc_type) { case DCC_READ_WRITE_TYPE: { if (link) { /* write new offset = 1 to continue * processing the list Loading @@ -255,12 +267,14 @@ static int __dcc_ll_cfg(struct dcc_drvdata *drvdata, int curr_list) dcc_sram_writel(drvdata, entry->mask, sram_offset); sram_offset += 4; dcc_sram_writel(drvdata, entry->rd_mod_wr, sram_offset); dcc_sram_writel(drvdata, entry->write_val, sram_offset); sram_offset += 4; continue; addr = 0; break; } if (entry->loop_cnt) { case DCC_LOOP_TYPE: { /* Check if we need to write link of prev entry */ if (link) { dcc_sram_writel(drvdata, link, sram_offset); Loading Loading @@ -292,23 +306,66 @@ static int __dcc_ll_cfg(struct dcc_drvdata *drvdata, int curr_list) prev_off = 0; prev_addr = addr; continue; break; } case DCC_WRITE_TYPE: { if (link) { /* write new offset = 1 to continue * processing the list */ link |= ((0x1 << 8) & BM(8, 14)); dcc_sram_writel(drvdata, link, sram_offset); sram_offset += 4; /* Reset link and prev_off */ addr = 0x00; prev_off = 0; prev_addr = addr; } off = entry->offset/4; /* write new offset-length pair to correct position */ link |= ((off & BM(0, 7)) | BIT(15) | ((entry->len << 8) & BM(8, 14))); link |= DCC_LINK_DESCRIPTOR; /* Address type */ addr = (entry->base >> 4) & BM(0, 27); addr |= DCC_ADDR_DESCRIPTOR; addr |= DCC_ADDR_DESCRIPTOR | DCC_WRITE_IND; dcc_sram_writel(drvdata, addr, sram_offset); sram_offset += 4; dcc_sram_writel(drvdata, link, sram_offset); sram_offset += 4; dcc_sram_writel(drvdata, entry->write_val, sram_offset); sram_offset += 4; addr = 0x00; link = 0; break; } default: { /* Address type */ addr = (entry->base >> 4) & BM(0, 27); addr |= DCC_ADDR_DESCRIPTOR | DCC_READ_IND; off = entry->offset/4; total_len += entry->len * 4; if (!prev_addr || prev_addr != addr || prev_off > off) { /* Check if we need to write link of prev entry */ /* Check if we need to write prev link entry */ if (link) { dcc_sram_writel(drvdata, link, sram_offset); dcc_sram_writel(drvdata, link, sram_offset); sram_offset += 4; } dev_err(drvdata->dev, "DCC: sram address.%d\n", sram_offset); dev_dbg(drvdata->dev, "DCC: sram address 0x%x\n", sram_offset); /* Write address */ dcc_sram_writel(drvdata, addr, sram_offset); Loading @@ -319,9 +376,10 @@ static int __dcc_ll_cfg(struct dcc_drvdata *drvdata, int curr_list) prev_off = 0; } if ((off - prev_off) > 0xFF || entry->len > MAX_DCC_LEN) { if ((off - prev_off) > 0xFF || entry->len > MAX_DCC_LEN) { dev_err(drvdata->dev, "DCC: Progamming error! Base: 0x%x, offset 0x%x.\n", "DCC: Progamming error Base: 0x%x, offset 0x%x\n", entry->base, entry->offset); ret = -EINVAL; goto err; Loading @@ -330,7 +388,8 @@ static int __dcc_ll_cfg(struct dcc_drvdata *drvdata, int curr_list) if (link) { /* * link already has one offset-length so new * offset-length needs to be placed at bits [29:15] * offset-length needs to be placed at * bits [29:15] */ pos = 15; Loading @@ -338,8 +397,8 @@ static int __dcc_ll_cfg(struct dcc_drvdata *drvdata, int curr_list) link &= BM(0, 14); } else { /* * link is empty, so new offset-length needs to be * placed at bits [15:0] * link is empty, so new offset-length needs * to be placed at bits [15:0] */ pos = 0; link = 1 << 15; Loading @@ -360,6 +419,8 @@ static int __dcc_ll_cfg(struct dcc_drvdata *drvdata, int curr_list) prev_off = off; prev_addr = addr; } } } if (link) { dcc_sram_writel(drvdata, link, sram_offset); Loading @@ -368,7 +429,7 @@ static int __dcc_ll_cfg(struct dcc_drvdata *drvdata, int curr_list) if (loop_start) { dev_err(drvdata->dev, "DCC: Progamming error! Loop unterminated.\n"); "DCC: Progamming error: Loop unterminated\n"); ret = -EINVAL; goto err; } Loading Loading @@ -457,7 +518,7 @@ static void __dcc_first_crc(struct dcc_drvdata *drvdata) */ for (i = 0; i < 2; i++) { if (!dcc_ready(drvdata)) dev_err(drvdata->dev, "DCC is not ready!\n"); dev_err(drvdata->dev, "DCC is not ready\n"); dcc_writel(drvdata, 1, DCC_LL_SW_TRIGGER(drvdata->curr_list)); Loading @@ -476,13 +537,13 @@ static int dcc_valid_list(struct dcc_drvdata *drvdata, int curr_list) return -EINVAL; if (drvdata->enable[curr_list]) { dev_err(drvdata->dev, "DCC is already enabled!\n"); dev_err(drvdata->dev, "DCC is already enabled\n"); return -EINVAL; } lock_reg = dcc_readl(drvdata, DCC_LL_LOCK(curr_list)); if (lock_reg & 0x1) { dev_err(drvdata->dev, "DCC is already enabled!\n"); dev_err(drvdata->dev, "DCC is already enabled\n"); return -EINVAL; } Loading Loading @@ -565,7 +626,7 @@ static void dcc_disable(struct dcc_drvdata *drvdata) mutex_lock(&drvdata->mutex); if (!dcc_ready(drvdata)) dev_err(drvdata->dev, "DCC is not ready! Disabling DCC...\n"); dev_err(drvdata->dev, "DCC is not ready Disabling DCC...\n"); for (curr_list = 0; curr_list < DCC_MAX_LINK_LIST; curr_list++) { if (!drvdata->enable[curr_list]) Loading Loading @@ -600,7 +661,7 @@ static ssize_t dcc_curr_list(struct device *dev, mutex_lock(&drvdata->mutex); lock_reg = dcc_readl(drvdata, DCC_LL_LOCK(val)); if (lock_reg & 0x1) { dev_err(drvdata->dev, "DCC linked list is already configured!\n"); dev_err(drvdata->dev, "DCC linked list is already configured\n"); mutex_unlock(&drvdata->mutex); return -EINVAL; } Loading Loading @@ -783,25 +844,34 @@ static ssize_t dcc_show_config(struct device *dev, mutex_lock(&drvdata->mutex); list_for_each_entry(entry, &drvdata->cfg_head[drvdata->curr_list], list) { if (entry->rd_wr_entry) switch (entry->desc_type) { case DCC_READ_WRITE_TYPE: len = snprintf(local_buf, 64, "Index: 0x%x, mask: 0x%x, val: 0x%x\n", entry->index, entry->mask, entry->rd_mod_wr); else if (entry->loop_cnt) entry->write_val); break; case DCC_LOOP_TYPE: len = snprintf(local_buf, 64, "Index: 0x%x, Loop: %d\n", entry->index, entry->loop_cnt); else break; case DCC_WRITE_TYPE: len = snprintf(local_buf, 64, "Index: 0x%x, Base: 0x%x, Offset: 0x%x, len: 0x%x\n", "Write Index: 0x%x, Base: 0x%x, Offset: 0x%x, len: 0x%x\n", entry->index, entry->base, entry->offset, entry->len); break; default: len = snprintf(local_buf, 64, "Read Index: 0x%x, Base: 0x%x, Offset: 0x%x, len: 0x%x\n", entry->index, entry->base, entry->offset, entry->len); } if ((count + len) > PAGE_SIZE) { dev_err(dev, "DCC: Couldn't write complete config!\n"); dev_err(dev, "DCC: Couldn't write complete config\n"); break; } strlcat(buf, local_buf, PAGE_SIZE); count += len; } Loading @@ -821,7 +891,7 @@ static int dcc_config_add(struct dcc_drvdata *drvdata, unsigned int addr, mutex_lock(&drvdata->mutex); if (!len) { dev_err(drvdata->dev, "DCC: Invalid length!\n"); dev_err(drvdata->dev, "DCC: Invalid length\n"); ret = -EINVAL; goto err; } Loading Loading @@ -883,6 +953,7 @@ static int dcc_config_add(struct dcc_drvdata *drvdata, unsigned int addr, entry->offset = offset; entry->len = min_t(uint32_t, len, MAX_DCC_LEN); entry->index = drvdata->nr_config[drvdata->curr_list]++; entry->desc_type = DCC_ADDR_TYPE; INIT_LIST_HEAD(&entry->list); list_add_tail(&entry->list, &drvdata->cfg_head[drvdata->curr_list]); Loading Loading @@ -1087,7 +1158,7 @@ static ssize_t dcc_rd_mod_wr(struct device *dev, } if (list_empty(&drvdata->cfg_head[drvdata->curr_list])) { dev_err(drvdata->dev, "DCC: No read address programmed!\n"); dev_err(drvdata->dev, "DCC: No read address programmed\n"); ret = -EPERM; goto err; } Loading @@ -1098,9 +1169,9 @@ static ssize_t dcc_rd_mod_wr(struct device *dev, goto err; } entry->rd_wr_entry = true; entry->desc_type = DCC_READ_WRITE_TYPE; entry->mask = mask; entry->rd_mod_wr = val; entry->write_val = val; entry->index = drvdata->nr_config[drvdata->curr_list]++; INIT_LIST_HEAD(&entry->list); list_add_tail(&entry->list, &drvdata->cfg_head[drvdata->curr_list]); Loading @@ -1110,6 +1181,50 @@ static ssize_t dcc_rd_mod_wr(struct device *dev, } static DEVICE_ATTR(rd_mod_wr, 0200, NULL, dcc_rd_mod_wr); static ssize_t dcc_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { int ret = size; int nval; unsigned int addr, write_val; struct dcc_drvdata *drvdata = dev_get_drvdata(dev); struct dcc_config_entry *entry; mutex_lock(&drvdata->mutex); nval = sscanf(buf, "%x %x", &addr, &write_val); if (drvdata->curr_list >= DCC_MAX_LINK_LIST) { dev_err(dev, "Select link list to program using curr_list\n"); return -EINVAL; } if (nval <= 1 || nval > 2) { ret = -EINVAL; goto err; } entry = devm_kzalloc(drvdata->dev, sizeof(*entry), GFP_KERNEL); if (!entry) { ret = -ENOMEM; goto err; } entry->desc_type = DCC_WRITE_TYPE; entry->base = addr & BM(4, 31); entry->offset = addr - entry->base; entry->write_val = write_val; entry->index = drvdata->nr_config[drvdata->curr_list]++; entry->len = 1; INIT_LIST_HEAD(&entry->list); list_add_tail(&entry->list, &drvdata->cfg_head[drvdata->curr_list]); err: mutex_unlock(&drvdata->mutex); return ret; } static DEVICE_ATTR(config_write, 0200, NULL, dcc_write); static const struct device_attribute *dcc_attrs[] = { &dev_attr_func_type, &dev_attr_data_sink, Loading @@ -1123,6 +1238,7 @@ static const struct device_attribute *dcc_attrs[] = { &dev_attr_loop, &dev_attr_rd_mod_wr, &dev_attr_curr_list, &dev_attr_config_write, NULL, }; Loading @@ -1134,7 +1250,7 @@ static int dcc_create_files(struct device *dev, for (i = 0; attrs[i] != NULL; i++) { ret = device_create_file(dev, attrs[i]); if (ret) { dev_err(dev, "DCC: Couldn't create sysfs attribute: %s!\n", dev_err(dev, "DCC: Couldn't create sysfs attribute: %s\n", attrs[i]->attr.name); break; } Loading Loading @@ -1173,7 +1289,7 @@ static ssize_t dcc_sram_read(struct file *file, char __user *data, if (copy_to_user(data, buf, len)) { dev_err(drvdata->dev, "DCC: Couldn't copy all data to user!\n"); "DCC: Couldn't copy all data to user\n"); kfree(buf); return -EFAULT; } Loading Loading @@ -1372,7 +1488,7 @@ static int dcc_probe(struct platform_device *pdev) } if (i == ARRAY_SIZE(str_dcc_data_sink)) { dev_err(dev, "Unknown sink type for DCC! Using '%s' as data sink\n", dev_err(dev, "Unknown sink type for DCC Using '%s' as data sink\n", str_dcc_data_sink[drvdata->data_sink]); } } Loading