Loading drivers/power/supply/qcom/fg-core.h +21 −1 Original line number Diff line number Diff line Loading @@ -67,6 +67,7 @@ #define MAX_LINE_LENGTH (ADDR_LEN + (ITEMS_PER_LINE * \ CHARS_PER_ITEM) + 1) \ #define NUM_PARTITIONS 3 #define FG_SRAM_ADDRESS_MAX 255 #define FG_SRAM_LEN 504 #define PROFILE_LEN 224 Loading Loading @@ -192,6 +193,18 @@ struct fg_sram_param { int val); }; struct fg_dma_address { /* Starting word address of the partition */ u16 partition_start; /* Last word address of the partition */ u16 partition_end; /* * Byte offset in the FG_DMA peripheral that maps to the partition_start * in SRAM */ u16 spmi_addr_base; }; enum fg_alg_flag_id { ALG_FLAG_SOC_LT_OTG_MIN = 0, ALG_FLAG_SOC_LT_RECHARGE, Loading Loading @@ -360,12 +373,12 @@ struct fg_chip { struct power_supply *parallel_psy; struct iio_channel *batt_id_chan; struct iio_channel *die_temp_chan; struct fg_memif *sram; struct fg_irq_info *irqs; struct votable *awake_votable; struct votable *delta_bsoc_irq_en_votable; struct votable *batt_miss_irq_en_votable; struct fg_sram_param *sp; struct fg_dma_address *addr_map; struct fg_alg_flag *alg_flags; int *debug_mask; char batt_profile[PROFILE_LEN]; Loading Loading @@ -409,8 +422,10 @@ struct fg_chip { bool esr_flt_cold_temp_en; bool slope_limit_en; bool use_ima_single_mode; bool use_dma; struct completion soc_update; struct completion soc_ready; struct completion mem_grant; struct delayed_work profile_load_work; struct work_struct status_change_work; struct work_struct cycle_count_work; Loading Loading @@ -459,10 +474,15 @@ extern int fg_interleaved_mem_read(struct fg_chip *chip, u16 address, u8 offset, u8 *val, int len); extern int fg_interleaved_mem_write(struct fg_chip *chip, u16 address, u8 offset, u8 *val, int len, bool atomic_access); extern int fg_direct_mem_read(struct fg_chip *chip, u16 address, u8 offset, u8 *val, int len); extern int fg_direct_mem_write(struct fg_chip *chip, u16 address, u8 offset, u8 *val, int len, bool atomic_access); extern int fg_read(struct fg_chip *chip, int addr, u8 *val, int len); extern int fg_write(struct fg_chip *chip, int addr, u8 *val, int len); extern int fg_masked_write(struct fg_chip *chip, int addr, u8 mask, u8 val); extern int fg_ima_init(struct fg_chip *chip); extern int fg_dma_init(struct fg_chip *chip); extern int fg_clear_ima_errors_if_any(struct fg_chip *chip, bool check_hw_sts); extern int fg_clear_dma_errors_if_any(struct fg_chip *chip); extern int fg_debugfs_create(struct fg_chip *chip); Loading drivers/power/supply/qcom/fg-memif.c +307 −0 Original line number Diff line number Diff line Loading @@ -746,6 +746,257 @@ int fg_interleaved_mem_write(struct fg_chip *chip, u16 address, u8 offset, return rc; } #define MEM_GRANT_WAIT_MS 200 static int fg_direct_mem_request(struct fg_chip *chip, bool request) { int rc, ret; u8 val, mask; bool tried_again = false; if (request) reinit_completion(&chip->mem_grant); mask = MEM_ACCESS_REQ_BIT | IACS_SLCT_BIT; val = request ? MEM_ACCESS_REQ_BIT : 0; rc = fg_masked_write(chip, MEM_IF_MEM_INTF_CFG(chip), mask, val); if (rc < 0) { pr_err("failed to configure mem_if_mem_intf_cfg rc=%d\n", rc); return rc; } mask = MEM_ARB_LO_LATENCY_EN_BIT | MEM_ARB_REQ_BIT; val = request ? mask : 0; rc = fg_masked_write(chip, MEM_IF_MEM_ARB_CFG(chip), mask, val); if (rc < 0) { pr_err("failed to configure mem_if_mem_arb_cfg rc:%d\n", rc); return rc; } if (request) pr_debug("requesting access\n"); else pr_debug("releasing access\n"); if (!request) return 0; wait: ret = wait_for_completion_interruptible_timeout( &chip->mem_grant, msecs_to_jiffies(MEM_GRANT_WAIT_MS)); /* If we were interrupted wait again one more time. */ if (ret <= 0) { if ((ret == -ERESTARTSYS || ret == 0) && !tried_again) { pr_debug("trying again, ret=%d\n", ret); tried_again = true; goto wait; } else { pr_err("wait for mem_grant timed out ret=%d\n", ret); } } if (ret <= 0) { val = 0; mask = MEM_ACCESS_REQ_BIT | IACS_SLCT_BIT; rc = fg_masked_write(chip, MEM_IF_MEM_INTF_CFG(chip), mask, val); if (rc < 0) { pr_err("failed to configure mem_if_mem_intf_cfg rc=%d\n", rc); return rc; } mask = MEM_ARB_LO_LATENCY_EN_BIT | MEM_ARB_REQ_BIT; rc = fg_masked_write(chip, MEM_IF_MEM_ARB_CFG(chip), mask, val); if (rc < 0) { pr_err("failed to configure mem_if_mem_arb_cfg rc:%d\n", rc); return rc; } return -ETIMEDOUT; } return rc; } static int fg_get_dma_address(struct fg_chip *chip, u16 sram_addr, u8 offset, u16 *addr) { int i; u16 start_sram_addr, end_sram_addr; for (i = 0; i < NUM_PARTITIONS; i++) { start_sram_addr = chip->addr_map[i].partition_start; end_sram_addr = chip->addr_map[i].partition_end; if (sram_addr >= start_sram_addr && sram_addr <= end_sram_addr) { *addr = chip->addr_map[i].spmi_addr_base + offset + (sram_addr - start_sram_addr) * BYTES_PER_SRAM_WORD; return 0; } } pr_err("Couldn't find address for %d from address map\n", sram_addr); return -ENXIO; } static int fg_get_partition_count(struct fg_chip *chip, u16 sram_addr, int len, int *count) { int i, num = 0; u16 end_addr, last_addr = 0; end_addr = sram_addr + len / BYTES_PER_SRAM_WORD; if (!(len % BYTES_PER_SRAM_WORD)) end_addr -= 1; if (sram_addr == end_addr) { *count = 1; return 0; } for (i = 0; i < NUM_PARTITIONS; i++) { pr_debug("address: %d last_addr: %d\n", sram_addr, last_addr); if (sram_addr >= chip->addr_map[i].partition_start && sram_addr <= chip->addr_map[i].partition_end && last_addr < end_addr) { num++; last_addr = chip->addr_map[i].partition_end; sram_addr = chip->addr_map[i+1].partition_start; } } if (num > 0) { *count = num; return 0; } pr_err("Couldn't find number of partitions for address %d\n", sram_addr); return -ENXIO; } static int fg_get_partition_avail_bytes(struct fg_chip *chip, u16 sram_addr, int len, int *rem_len) { int i, part_len = 0, temp; u16 end_addr; for (i = 0; i < NUM_PARTITIONS; i++) { if (sram_addr >= chip->addr_map[i].partition_start && sram_addr <= chip->addr_map[i].partition_end) { part_len = (chip->addr_map[i].partition_end - chip->addr_map[i].partition_start + 1); part_len *= BYTES_PER_SRAM_WORD; end_addr = chip->addr_map[i].partition_end; break; } } if (part_len <= 0) { pr_err("Bad address? total_len=%d\n", part_len); return -ENXIO; } temp = (end_addr - sram_addr + 1) * BYTES_PER_SRAM_WORD; if (temp > part_len || !temp) { pr_err("Bad length=%d\n", temp); return -ENXIO; } *rem_len = temp; pr_debug("address %d len %d rem_len %d\n", sram_addr, len, *rem_len); return 0; } static int __fg_direct_mem_rw(struct fg_chip *chip, u16 sram_addr, u8 offset, u8 *val, int len, bool access) { int rc, ret, num_partitions, num_bytes = 0; u16 addr; u8 *ptr = val; char *temp_str; if (offset > 3) { pr_err("offset too large %d\n", offset); return -EINVAL; } rc = fg_get_partition_count(chip, sram_addr, len, &num_partitions); if (rc < 0) return rc; pr_debug("number of partitions: %d\n", num_partitions); rc = fg_direct_mem_request(chip, true); if (rc < 0) { pr_err("Error in requesting direct_mem access rc=%d\n", rc); return rc; } while (num_partitions-- && len) { rc = fg_get_dma_address(chip, sram_addr, offset, &addr); if (rc < 0) { pr_err("Incorrect address %d/offset %d\n", sram_addr, offset); break; } rc = fg_get_partition_avail_bytes(chip, sram_addr + offset, len, &num_bytes); if (rc < 0) break; if (num_bytes > len) num_bytes = len; pr_debug("reading from address: [%d %d] dma_address = %x\n", sram_addr, offset, addr); if (access == FG_READ) { rc = fg_read(chip, addr, ptr, num_bytes); temp_str = "read"; } else { rc = fg_write(chip, addr, ptr, num_bytes); temp_str = "write"; } if (rc < 0) { pr_err("Error in %sing address %d rc=%d\n", temp_str, sram_addr, rc); break; } ptr += num_bytes; len -= num_bytes; sram_addr += (num_bytes / BYTES_PER_SRAM_WORD); offset = 0; } ret = fg_direct_mem_request(chip, false); if (ret < 0) { pr_err("Error in releasing direct_mem access rc=%d\n", rc); return ret; } return rc; } int fg_direct_mem_read(struct fg_chip *chip, u16 sram_addr, u8 offset, u8 *val, int len) { return __fg_direct_mem_rw(chip, sram_addr, offset, val, len, FG_READ); } int fg_direct_mem_write(struct fg_chip *chip, u16 sram_addr, u8 offset, u8 *val, int len, bool atomic_access) { return __fg_direct_mem_rw(chip, sram_addr, offset, val, len, FG_WRITE); } int fg_ima_init(struct fg_chip *chip) { int rc; Loading Loading @@ -778,3 +1029,59 @@ int fg_ima_init(struct fg_chip *chip) return 0; } /* * This SRAM partition to DMA address partition mapping remains identical for * PMICs that use GEN3 FG. */ static struct fg_dma_address fg_gen3_addr_map[NUM_PARTITIONS] = { /* system partition */ { .partition_start = 0, .partition_end = 23, .spmi_addr_base = FG_DMA0_BASE + SRAM_ADDR_OFFSET, }, /* battery profile partition */ { .partition_start = 24, .partition_end = 79, .spmi_addr_base = FG_DMA1_BASE + SRAM_ADDR_OFFSET, }, /* scratch pad partition */ { .partition_start = 80, .partition_end = 125, .spmi_addr_base = FG_DMA2_BASE + SRAM_ADDR_OFFSET, }, }; int fg_dma_init(struct fg_chip *chip) { int rc; chip->addr_map = fg_gen3_addr_map; /* Clear DMA errors if any before clearing IMA errors */ rc = fg_clear_dma_errors_if_any(chip); if (rc < 0) { pr_err("Error in checking DMA errors rc:%d\n", rc); return rc; } /* Configure the DMA peripheral addressing to partition */ rc = fg_masked_write(chip, MEM_IF_DMA_CTL(chip), ADDR_KIND_BIT, ADDR_KIND_BIT); if (rc < 0) { pr_err("failed to configure DMA_CTL rc:%d\n", rc); return rc; } /* Release the DMA initially so that request can happen */ rc = fg_direct_mem_request(chip, false); if (rc < 0) { pr_err("Error in releasing direct_mem access rc=%d\n", rc); return rc; } return 0; } drivers/power/supply/qcom/fg-reg.h +15 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ #define BATT_SOC_LOW_PWR_STS(chip) (chip->batt_soc_base + 0x56) /* BATT_SOC_INT_RT_STS */ #define SOC_READY_BIT BIT(1) #define MSOC_EMPTY_BIT BIT(5) /* BATT_SOC_EN_CTL */ Loading Loading @@ -266,6 +267,7 @@ /* FG_MEM_IF register and bit definitions */ #define MEM_IF_INT_RT_STS(chip) ((chip->mem_if_base) + 0x10) #define MEM_IF_MEM_ARB_CFG(chip) ((chip->mem_if_base) + 0x40) #define MEM_IF_MEM_INTF_CFG(chip) ((chip->mem_if_base) + 0x50) #define MEM_IF_IMA_CTL(chip) ((chip->mem_if_base) + 0x51) #define MEM_IF_IMA_CFG(chip) ((chip->mem_if_base) + 0x52) Loading @@ -286,6 +288,11 @@ /* MEM_IF_INT_RT_STS */ #define MEM_XCP_BIT BIT(1) #define MEM_GNT_BIT BIT(2) /* MEM_IF_MEM_ARB_CFG */ #define MEM_ARB_LO_LATENCY_EN_BIT BIT(1) #define MEM_ARB_REQ_BIT BIT(0) /* MEM_IF_MEM_INTF_CFG */ #define MEM_ACCESS_REQ_BIT BIT(7) Loading Loading @@ -325,5 +332,13 @@ #define DMA_READ_ERROR_BIT BIT(2) /* MEM_IF_DMA_CTL */ #define ADDR_KIND_BIT BIT(1) #define DMA_CLEAR_LOG_BIT BIT(0) /* FG_DMAx */ #define FG_DMA0_BASE 0x4800 #define FG_DMA1_BASE 0x4900 #define FG_DMA2_BASE 0x4A00 #define FG_DMA3_BASE 0x4B00 #define SRAM_ADDR_OFFSET 0x20 #endif drivers/power/supply/qcom/fg-util.c +14 −5 Original line number Diff line number Diff line Loading @@ -255,8 +255,6 @@ int fg_sram_write(struct fg_chip *chip, u16 address, u8 offset, reinit_completion(&chip->soc_update); enable_irq(chip->irqs[SOC_UPDATE_IRQ].irq); atomic_access = true; } else { flags = FG_IMA_DEFAULT; } wait: /* Loading @@ -282,11 +280,17 @@ int fg_sram_write(struct fg_chip *chip, u16 address, u8 offset, } } if (chip->use_dma) rc = fg_direct_mem_write(chip, address, offset, val, len, false); else rc = fg_interleaved_mem_write(chip, address, offset, val, len, atomic_access); if (rc < 0) pr_err("Error in writing SRAM address 0x%x[%d], rc=%d\n", address, offset, rc); out: if (atomic_access) disable_irq_nosync(chip->irqs[SOC_UPDATE_IRQ].irq); Loading @@ -313,9 +317,14 @@ int fg_sram_read(struct fg_chip *chip, u16 address, u8 offset, if (!(flags & FG_IMA_NO_WLOCK)) vote(chip->awake_votable, SRAM_READ, true, 0); mutex_lock(&chip->sram_rw_lock); if (chip->use_dma) rc = fg_direct_mem_read(chip, address, offset, val, len); else rc = fg_interleaved_mem_read(chip, address, offset, val, len); if (rc < 0) pr_err("Error in reading SRAM address 0x%x[%d], rc=%d\n", address, offset, rc); Loading drivers/power/supply/qcom/qpnp-fg-gen3.c +47 −21 Original line number Diff line number Diff line Loading @@ -533,7 +533,7 @@ static int fg_get_sram_prop(struct fg_chip *chip, enum fg_sram_param_id id, rc = fg_sram_read(chip, chip->sp[id].addr_word, chip->sp[id].addr_byte, buf, chip->sp[id].len, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error reading address 0x%04x[%d] rc=%d\n", pr_err("Error reading address %d[%d] rc=%d\n", chip->sp[id].addr_word, chip->sp[id].addr_byte, rc); return rc; } Loading Loading @@ -3503,6 +3503,9 @@ static int fg_hw_init(struct fg_chip *chip) static int fg_memif_init(struct fg_chip *chip) { if (chip->use_dma) return fg_dma_init(chip); return fg_ima_init(chip); } Loading Loading @@ -3542,6 +3545,26 @@ static int fg_adjust_timebase(struct fg_chip *chip) /* INTERRUPT HANDLERS STAY HERE */ static irqreturn_t fg_dma_grant_irq_handler(int irq, void *data) { struct fg_chip *chip = data; u8 status; int rc; rc = fg_read(chip, MEM_IF_INT_RT_STS(chip), &status, 1); if (rc < 0) { pr_err("failed to read addr=0x%04x, rc=%d\n", MEM_IF_INT_RT_STS(chip), rc); return IRQ_HANDLED; } fg_dbg(chip, FG_IRQ, "irq %d triggered, status:%d\n", irq, status); if (status & MEM_GNT_BIT) complete_all(&chip->mem_grant); return IRQ_HANDLED; } static irqreturn_t fg_mem_xcp_irq_handler(int irq, void *data) { struct fg_chip *chip = data; Loading Loading @@ -3822,7 +3845,8 @@ static struct fg_irq_info fg_irqs[FG_IRQ_MAX] = { /* MEM_IF irqs */ [DMA_GRANT_IRQ] = { .name = "dma-grant", .handler = fg_dummy_irq_handler, .handler = fg_dma_grant_irq_handler, .wakeable = true, }, [MEM_XCP_IRQ] = { .name = "mem-xcp", Loading Loading @@ -4046,6 +4070,7 @@ static int fg_parse_dt(struct fg_chip *chip) switch (chip->pmic_rev_id->pmic_subtype) { case PMI8998_SUBTYPE: chip->use_dma = true; if (chip->pmic_rev_id->rev4 < PMI8998_V2P0_REV4) { chip->sp = pmi8998_v1_sram_params; chip->alg_flags = pmi8998_v1_alg_flags; Loading Loading @@ -4466,6 +4491,7 @@ static int fg_gen3_probe(struct platform_device *pdev) mutex_init(&chip->charge_full_lock); init_completion(&chip->soc_update); init_completion(&chip->soc_ready); init_completion(&chip->mem_grant); INIT_DELAYED_WORK(&chip->profile_load_work, profile_load_work); INIT_WORK(&chip->status_change_work, status_change_work); INIT_WORK(&chip->cycle_count_work, cycle_count_work); Loading @@ -4479,6 +4505,25 @@ static int fg_gen3_probe(struct platform_device *pdev) goto exit; } platform_set_drvdata(pdev, chip); rc = fg_register_interrupts(chip); if (rc < 0) { dev_err(chip->dev, "Error in registering interrupts, rc:%d\n", rc); goto exit; } /* Keep SOC_UPDATE irq disabled until we require it */ if (fg_irqs[SOC_UPDATE_IRQ].irq) disable_irq_nosync(fg_irqs[SOC_UPDATE_IRQ].irq); /* Keep BSOC_DELTA_IRQ disabled until we require it */ vote(chip->delta_bsoc_irq_en_votable, DELTA_BSOC_IRQ_VOTER, false, 0); /* Keep BATT_MISSING_IRQ disabled until we require it */ vote(chip->batt_miss_irq_en_votable, BATT_MISS_IRQ_VOTER, false, 0); rc = fg_hw_init(chip); if (rc < 0) { dev_err(chip->dev, "Error in initializing FG hardware, rc:%d\n", Loading @@ -4486,8 +4531,6 @@ static int fg_gen3_probe(struct platform_device *pdev) goto exit; } platform_set_drvdata(pdev, chip); /* Register the power supply */ fg_psy_cfg.drv_data = chip; fg_psy_cfg.of_node = NULL; Loading @@ -4508,23 +4551,6 @@ static int fg_gen3_probe(struct platform_device *pdev) goto exit; } rc = fg_register_interrupts(chip); if (rc < 0) { dev_err(chip->dev, "Error in registering interrupts, rc:%d\n", rc); goto exit; } /* Keep SOC_UPDATE_IRQ disabled until we require it */ if (fg_irqs[SOC_UPDATE_IRQ].irq) disable_irq_nosync(fg_irqs[SOC_UPDATE_IRQ].irq); /* Keep BSOC_DELTA_IRQ disabled until we require it */ vote(chip->delta_bsoc_irq_en_votable, DELTA_BSOC_IRQ_VOTER, false, 0); /* Keep BATT_MISSING_IRQ disabled until we require it */ vote(chip->batt_miss_irq_en_votable, BATT_MISS_IRQ_VOTER, false, 0); rc = fg_debugfs_create(chip); if (rc < 0) { dev_err(chip->dev, "Error in creating debugfs entries, rc:%d\n", Loading Loading
drivers/power/supply/qcom/fg-core.h +21 −1 Original line number Diff line number Diff line Loading @@ -67,6 +67,7 @@ #define MAX_LINE_LENGTH (ADDR_LEN + (ITEMS_PER_LINE * \ CHARS_PER_ITEM) + 1) \ #define NUM_PARTITIONS 3 #define FG_SRAM_ADDRESS_MAX 255 #define FG_SRAM_LEN 504 #define PROFILE_LEN 224 Loading Loading @@ -192,6 +193,18 @@ struct fg_sram_param { int val); }; struct fg_dma_address { /* Starting word address of the partition */ u16 partition_start; /* Last word address of the partition */ u16 partition_end; /* * Byte offset in the FG_DMA peripheral that maps to the partition_start * in SRAM */ u16 spmi_addr_base; }; enum fg_alg_flag_id { ALG_FLAG_SOC_LT_OTG_MIN = 0, ALG_FLAG_SOC_LT_RECHARGE, Loading Loading @@ -360,12 +373,12 @@ struct fg_chip { struct power_supply *parallel_psy; struct iio_channel *batt_id_chan; struct iio_channel *die_temp_chan; struct fg_memif *sram; struct fg_irq_info *irqs; struct votable *awake_votable; struct votable *delta_bsoc_irq_en_votable; struct votable *batt_miss_irq_en_votable; struct fg_sram_param *sp; struct fg_dma_address *addr_map; struct fg_alg_flag *alg_flags; int *debug_mask; char batt_profile[PROFILE_LEN]; Loading Loading @@ -409,8 +422,10 @@ struct fg_chip { bool esr_flt_cold_temp_en; bool slope_limit_en; bool use_ima_single_mode; bool use_dma; struct completion soc_update; struct completion soc_ready; struct completion mem_grant; struct delayed_work profile_load_work; struct work_struct status_change_work; struct work_struct cycle_count_work; Loading Loading @@ -459,10 +474,15 @@ extern int fg_interleaved_mem_read(struct fg_chip *chip, u16 address, u8 offset, u8 *val, int len); extern int fg_interleaved_mem_write(struct fg_chip *chip, u16 address, u8 offset, u8 *val, int len, bool atomic_access); extern int fg_direct_mem_read(struct fg_chip *chip, u16 address, u8 offset, u8 *val, int len); extern int fg_direct_mem_write(struct fg_chip *chip, u16 address, u8 offset, u8 *val, int len, bool atomic_access); extern int fg_read(struct fg_chip *chip, int addr, u8 *val, int len); extern int fg_write(struct fg_chip *chip, int addr, u8 *val, int len); extern int fg_masked_write(struct fg_chip *chip, int addr, u8 mask, u8 val); extern int fg_ima_init(struct fg_chip *chip); extern int fg_dma_init(struct fg_chip *chip); extern int fg_clear_ima_errors_if_any(struct fg_chip *chip, bool check_hw_sts); extern int fg_clear_dma_errors_if_any(struct fg_chip *chip); extern int fg_debugfs_create(struct fg_chip *chip); Loading
drivers/power/supply/qcom/fg-memif.c +307 −0 Original line number Diff line number Diff line Loading @@ -746,6 +746,257 @@ int fg_interleaved_mem_write(struct fg_chip *chip, u16 address, u8 offset, return rc; } #define MEM_GRANT_WAIT_MS 200 static int fg_direct_mem_request(struct fg_chip *chip, bool request) { int rc, ret; u8 val, mask; bool tried_again = false; if (request) reinit_completion(&chip->mem_grant); mask = MEM_ACCESS_REQ_BIT | IACS_SLCT_BIT; val = request ? MEM_ACCESS_REQ_BIT : 0; rc = fg_masked_write(chip, MEM_IF_MEM_INTF_CFG(chip), mask, val); if (rc < 0) { pr_err("failed to configure mem_if_mem_intf_cfg rc=%d\n", rc); return rc; } mask = MEM_ARB_LO_LATENCY_EN_BIT | MEM_ARB_REQ_BIT; val = request ? mask : 0; rc = fg_masked_write(chip, MEM_IF_MEM_ARB_CFG(chip), mask, val); if (rc < 0) { pr_err("failed to configure mem_if_mem_arb_cfg rc:%d\n", rc); return rc; } if (request) pr_debug("requesting access\n"); else pr_debug("releasing access\n"); if (!request) return 0; wait: ret = wait_for_completion_interruptible_timeout( &chip->mem_grant, msecs_to_jiffies(MEM_GRANT_WAIT_MS)); /* If we were interrupted wait again one more time. */ if (ret <= 0) { if ((ret == -ERESTARTSYS || ret == 0) && !tried_again) { pr_debug("trying again, ret=%d\n", ret); tried_again = true; goto wait; } else { pr_err("wait for mem_grant timed out ret=%d\n", ret); } } if (ret <= 0) { val = 0; mask = MEM_ACCESS_REQ_BIT | IACS_SLCT_BIT; rc = fg_masked_write(chip, MEM_IF_MEM_INTF_CFG(chip), mask, val); if (rc < 0) { pr_err("failed to configure mem_if_mem_intf_cfg rc=%d\n", rc); return rc; } mask = MEM_ARB_LO_LATENCY_EN_BIT | MEM_ARB_REQ_BIT; rc = fg_masked_write(chip, MEM_IF_MEM_ARB_CFG(chip), mask, val); if (rc < 0) { pr_err("failed to configure mem_if_mem_arb_cfg rc:%d\n", rc); return rc; } return -ETIMEDOUT; } return rc; } static int fg_get_dma_address(struct fg_chip *chip, u16 sram_addr, u8 offset, u16 *addr) { int i; u16 start_sram_addr, end_sram_addr; for (i = 0; i < NUM_PARTITIONS; i++) { start_sram_addr = chip->addr_map[i].partition_start; end_sram_addr = chip->addr_map[i].partition_end; if (sram_addr >= start_sram_addr && sram_addr <= end_sram_addr) { *addr = chip->addr_map[i].spmi_addr_base + offset + (sram_addr - start_sram_addr) * BYTES_PER_SRAM_WORD; return 0; } } pr_err("Couldn't find address for %d from address map\n", sram_addr); return -ENXIO; } static int fg_get_partition_count(struct fg_chip *chip, u16 sram_addr, int len, int *count) { int i, num = 0; u16 end_addr, last_addr = 0; end_addr = sram_addr + len / BYTES_PER_SRAM_WORD; if (!(len % BYTES_PER_SRAM_WORD)) end_addr -= 1; if (sram_addr == end_addr) { *count = 1; return 0; } for (i = 0; i < NUM_PARTITIONS; i++) { pr_debug("address: %d last_addr: %d\n", sram_addr, last_addr); if (sram_addr >= chip->addr_map[i].partition_start && sram_addr <= chip->addr_map[i].partition_end && last_addr < end_addr) { num++; last_addr = chip->addr_map[i].partition_end; sram_addr = chip->addr_map[i+1].partition_start; } } if (num > 0) { *count = num; return 0; } pr_err("Couldn't find number of partitions for address %d\n", sram_addr); return -ENXIO; } static int fg_get_partition_avail_bytes(struct fg_chip *chip, u16 sram_addr, int len, int *rem_len) { int i, part_len = 0, temp; u16 end_addr; for (i = 0; i < NUM_PARTITIONS; i++) { if (sram_addr >= chip->addr_map[i].partition_start && sram_addr <= chip->addr_map[i].partition_end) { part_len = (chip->addr_map[i].partition_end - chip->addr_map[i].partition_start + 1); part_len *= BYTES_PER_SRAM_WORD; end_addr = chip->addr_map[i].partition_end; break; } } if (part_len <= 0) { pr_err("Bad address? total_len=%d\n", part_len); return -ENXIO; } temp = (end_addr - sram_addr + 1) * BYTES_PER_SRAM_WORD; if (temp > part_len || !temp) { pr_err("Bad length=%d\n", temp); return -ENXIO; } *rem_len = temp; pr_debug("address %d len %d rem_len %d\n", sram_addr, len, *rem_len); return 0; } static int __fg_direct_mem_rw(struct fg_chip *chip, u16 sram_addr, u8 offset, u8 *val, int len, bool access) { int rc, ret, num_partitions, num_bytes = 0; u16 addr; u8 *ptr = val; char *temp_str; if (offset > 3) { pr_err("offset too large %d\n", offset); return -EINVAL; } rc = fg_get_partition_count(chip, sram_addr, len, &num_partitions); if (rc < 0) return rc; pr_debug("number of partitions: %d\n", num_partitions); rc = fg_direct_mem_request(chip, true); if (rc < 0) { pr_err("Error in requesting direct_mem access rc=%d\n", rc); return rc; } while (num_partitions-- && len) { rc = fg_get_dma_address(chip, sram_addr, offset, &addr); if (rc < 0) { pr_err("Incorrect address %d/offset %d\n", sram_addr, offset); break; } rc = fg_get_partition_avail_bytes(chip, sram_addr + offset, len, &num_bytes); if (rc < 0) break; if (num_bytes > len) num_bytes = len; pr_debug("reading from address: [%d %d] dma_address = %x\n", sram_addr, offset, addr); if (access == FG_READ) { rc = fg_read(chip, addr, ptr, num_bytes); temp_str = "read"; } else { rc = fg_write(chip, addr, ptr, num_bytes); temp_str = "write"; } if (rc < 0) { pr_err("Error in %sing address %d rc=%d\n", temp_str, sram_addr, rc); break; } ptr += num_bytes; len -= num_bytes; sram_addr += (num_bytes / BYTES_PER_SRAM_WORD); offset = 0; } ret = fg_direct_mem_request(chip, false); if (ret < 0) { pr_err("Error in releasing direct_mem access rc=%d\n", rc); return ret; } return rc; } int fg_direct_mem_read(struct fg_chip *chip, u16 sram_addr, u8 offset, u8 *val, int len) { return __fg_direct_mem_rw(chip, sram_addr, offset, val, len, FG_READ); } int fg_direct_mem_write(struct fg_chip *chip, u16 sram_addr, u8 offset, u8 *val, int len, bool atomic_access) { return __fg_direct_mem_rw(chip, sram_addr, offset, val, len, FG_WRITE); } int fg_ima_init(struct fg_chip *chip) { int rc; Loading Loading @@ -778,3 +1029,59 @@ int fg_ima_init(struct fg_chip *chip) return 0; } /* * This SRAM partition to DMA address partition mapping remains identical for * PMICs that use GEN3 FG. */ static struct fg_dma_address fg_gen3_addr_map[NUM_PARTITIONS] = { /* system partition */ { .partition_start = 0, .partition_end = 23, .spmi_addr_base = FG_DMA0_BASE + SRAM_ADDR_OFFSET, }, /* battery profile partition */ { .partition_start = 24, .partition_end = 79, .spmi_addr_base = FG_DMA1_BASE + SRAM_ADDR_OFFSET, }, /* scratch pad partition */ { .partition_start = 80, .partition_end = 125, .spmi_addr_base = FG_DMA2_BASE + SRAM_ADDR_OFFSET, }, }; int fg_dma_init(struct fg_chip *chip) { int rc; chip->addr_map = fg_gen3_addr_map; /* Clear DMA errors if any before clearing IMA errors */ rc = fg_clear_dma_errors_if_any(chip); if (rc < 0) { pr_err("Error in checking DMA errors rc:%d\n", rc); return rc; } /* Configure the DMA peripheral addressing to partition */ rc = fg_masked_write(chip, MEM_IF_DMA_CTL(chip), ADDR_KIND_BIT, ADDR_KIND_BIT); if (rc < 0) { pr_err("failed to configure DMA_CTL rc:%d\n", rc); return rc; } /* Release the DMA initially so that request can happen */ rc = fg_direct_mem_request(chip, false); if (rc < 0) { pr_err("Error in releasing direct_mem access rc=%d\n", rc); return rc; } return 0; }
drivers/power/supply/qcom/fg-reg.h +15 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ #define BATT_SOC_LOW_PWR_STS(chip) (chip->batt_soc_base + 0x56) /* BATT_SOC_INT_RT_STS */ #define SOC_READY_BIT BIT(1) #define MSOC_EMPTY_BIT BIT(5) /* BATT_SOC_EN_CTL */ Loading Loading @@ -266,6 +267,7 @@ /* FG_MEM_IF register and bit definitions */ #define MEM_IF_INT_RT_STS(chip) ((chip->mem_if_base) + 0x10) #define MEM_IF_MEM_ARB_CFG(chip) ((chip->mem_if_base) + 0x40) #define MEM_IF_MEM_INTF_CFG(chip) ((chip->mem_if_base) + 0x50) #define MEM_IF_IMA_CTL(chip) ((chip->mem_if_base) + 0x51) #define MEM_IF_IMA_CFG(chip) ((chip->mem_if_base) + 0x52) Loading @@ -286,6 +288,11 @@ /* MEM_IF_INT_RT_STS */ #define MEM_XCP_BIT BIT(1) #define MEM_GNT_BIT BIT(2) /* MEM_IF_MEM_ARB_CFG */ #define MEM_ARB_LO_LATENCY_EN_BIT BIT(1) #define MEM_ARB_REQ_BIT BIT(0) /* MEM_IF_MEM_INTF_CFG */ #define MEM_ACCESS_REQ_BIT BIT(7) Loading Loading @@ -325,5 +332,13 @@ #define DMA_READ_ERROR_BIT BIT(2) /* MEM_IF_DMA_CTL */ #define ADDR_KIND_BIT BIT(1) #define DMA_CLEAR_LOG_BIT BIT(0) /* FG_DMAx */ #define FG_DMA0_BASE 0x4800 #define FG_DMA1_BASE 0x4900 #define FG_DMA2_BASE 0x4A00 #define FG_DMA3_BASE 0x4B00 #define SRAM_ADDR_OFFSET 0x20 #endif
drivers/power/supply/qcom/fg-util.c +14 −5 Original line number Diff line number Diff line Loading @@ -255,8 +255,6 @@ int fg_sram_write(struct fg_chip *chip, u16 address, u8 offset, reinit_completion(&chip->soc_update); enable_irq(chip->irqs[SOC_UPDATE_IRQ].irq); atomic_access = true; } else { flags = FG_IMA_DEFAULT; } wait: /* Loading @@ -282,11 +280,17 @@ int fg_sram_write(struct fg_chip *chip, u16 address, u8 offset, } } if (chip->use_dma) rc = fg_direct_mem_write(chip, address, offset, val, len, false); else rc = fg_interleaved_mem_write(chip, address, offset, val, len, atomic_access); if (rc < 0) pr_err("Error in writing SRAM address 0x%x[%d], rc=%d\n", address, offset, rc); out: if (atomic_access) disable_irq_nosync(chip->irqs[SOC_UPDATE_IRQ].irq); Loading @@ -313,9 +317,14 @@ int fg_sram_read(struct fg_chip *chip, u16 address, u8 offset, if (!(flags & FG_IMA_NO_WLOCK)) vote(chip->awake_votable, SRAM_READ, true, 0); mutex_lock(&chip->sram_rw_lock); if (chip->use_dma) rc = fg_direct_mem_read(chip, address, offset, val, len); else rc = fg_interleaved_mem_read(chip, address, offset, val, len); if (rc < 0) pr_err("Error in reading SRAM address 0x%x[%d], rc=%d\n", address, offset, rc); Loading
drivers/power/supply/qcom/qpnp-fg-gen3.c +47 −21 Original line number Diff line number Diff line Loading @@ -533,7 +533,7 @@ static int fg_get_sram_prop(struct fg_chip *chip, enum fg_sram_param_id id, rc = fg_sram_read(chip, chip->sp[id].addr_word, chip->sp[id].addr_byte, buf, chip->sp[id].len, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error reading address 0x%04x[%d] rc=%d\n", pr_err("Error reading address %d[%d] rc=%d\n", chip->sp[id].addr_word, chip->sp[id].addr_byte, rc); return rc; } Loading Loading @@ -3503,6 +3503,9 @@ static int fg_hw_init(struct fg_chip *chip) static int fg_memif_init(struct fg_chip *chip) { if (chip->use_dma) return fg_dma_init(chip); return fg_ima_init(chip); } Loading Loading @@ -3542,6 +3545,26 @@ static int fg_adjust_timebase(struct fg_chip *chip) /* INTERRUPT HANDLERS STAY HERE */ static irqreturn_t fg_dma_grant_irq_handler(int irq, void *data) { struct fg_chip *chip = data; u8 status; int rc; rc = fg_read(chip, MEM_IF_INT_RT_STS(chip), &status, 1); if (rc < 0) { pr_err("failed to read addr=0x%04x, rc=%d\n", MEM_IF_INT_RT_STS(chip), rc); return IRQ_HANDLED; } fg_dbg(chip, FG_IRQ, "irq %d triggered, status:%d\n", irq, status); if (status & MEM_GNT_BIT) complete_all(&chip->mem_grant); return IRQ_HANDLED; } static irqreturn_t fg_mem_xcp_irq_handler(int irq, void *data) { struct fg_chip *chip = data; Loading Loading @@ -3822,7 +3845,8 @@ static struct fg_irq_info fg_irqs[FG_IRQ_MAX] = { /* MEM_IF irqs */ [DMA_GRANT_IRQ] = { .name = "dma-grant", .handler = fg_dummy_irq_handler, .handler = fg_dma_grant_irq_handler, .wakeable = true, }, [MEM_XCP_IRQ] = { .name = "mem-xcp", Loading Loading @@ -4046,6 +4070,7 @@ static int fg_parse_dt(struct fg_chip *chip) switch (chip->pmic_rev_id->pmic_subtype) { case PMI8998_SUBTYPE: chip->use_dma = true; if (chip->pmic_rev_id->rev4 < PMI8998_V2P0_REV4) { chip->sp = pmi8998_v1_sram_params; chip->alg_flags = pmi8998_v1_alg_flags; Loading Loading @@ -4466,6 +4491,7 @@ static int fg_gen3_probe(struct platform_device *pdev) mutex_init(&chip->charge_full_lock); init_completion(&chip->soc_update); init_completion(&chip->soc_ready); init_completion(&chip->mem_grant); INIT_DELAYED_WORK(&chip->profile_load_work, profile_load_work); INIT_WORK(&chip->status_change_work, status_change_work); INIT_WORK(&chip->cycle_count_work, cycle_count_work); Loading @@ -4479,6 +4505,25 @@ static int fg_gen3_probe(struct platform_device *pdev) goto exit; } platform_set_drvdata(pdev, chip); rc = fg_register_interrupts(chip); if (rc < 0) { dev_err(chip->dev, "Error in registering interrupts, rc:%d\n", rc); goto exit; } /* Keep SOC_UPDATE irq disabled until we require it */ if (fg_irqs[SOC_UPDATE_IRQ].irq) disable_irq_nosync(fg_irqs[SOC_UPDATE_IRQ].irq); /* Keep BSOC_DELTA_IRQ disabled until we require it */ vote(chip->delta_bsoc_irq_en_votable, DELTA_BSOC_IRQ_VOTER, false, 0); /* Keep BATT_MISSING_IRQ disabled until we require it */ vote(chip->batt_miss_irq_en_votable, BATT_MISS_IRQ_VOTER, false, 0); rc = fg_hw_init(chip); if (rc < 0) { dev_err(chip->dev, "Error in initializing FG hardware, rc:%d\n", Loading @@ -4486,8 +4531,6 @@ static int fg_gen3_probe(struct platform_device *pdev) goto exit; } platform_set_drvdata(pdev, chip); /* Register the power supply */ fg_psy_cfg.drv_data = chip; fg_psy_cfg.of_node = NULL; Loading @@ -4508,23 +4551,6 @@ static int fg_gen3_probe(struct platform_device *pdev) goto exit; } rc = fg_register_interrupts(chip); if (rc < 0) { dev_err(chip->dev, "Error in registering interrupts, rc:%d\n", rc); goto exit; } /* Keep SOC_UPDATE_IRQ disabled until we require it */ if (fg_irqs[SOC_UPDATE_IRQ].irq) disable_irq_nosync(fg_irqs[SOC_UPDATE_IRQ].irq); /* Keep BSOC_DELTA_IRQ disabled until we require it */ vote(chip->delta_bsoc_irq_en_votable, DELTA_BSOC_IRQ_VOTER, false, 0); /* Keep BATT_MISSING_IRQ disabled until we require it */ vote(chip->batt_miss_irq_en_votable, BATT_MISS_IRQ_VOTER, false, 0); rc = fg_debugfs_create(chip); if (rc < 0) { dev_err(chip->dev, "Error in creating debugfs entries, rc:%d\n", Loading