diff options
author | Ansuel Smith <ansuelsmth@gmail.com> | 2022-01-11 12:41:35 +0100 |
---|---|---|
committer | Daniel Golle <daniel@makrotopia.org> | 2022-03-27 16:16:07 +0100 |
commit | 327677a71d74cc8230d54ecb63341347861fe065 (patch) | |
tree | 3e1cb36eab01da86297f25f021e94be1cb5924c5 /target/linux/ipq806x | |
parent | 4c5d5c66ca443d3570c14a6b3ccae5041d52fef0 (diff) | |
download | upstream-327677a71d74cc8230d54ecb63341347861fe065.tar.gz upstream-327677a71d74cc8230d54ecb63341347861fe065.tar.bz2 upstream-327677a71d74cc8230d54ecb63341347861fe065.zip |
ipq806x: 5:15: drop upstream patch
- Drop stmmac upstream patches
- Drop tsens patches
- Drop ADM driver
- Drop SMEM parser
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
Diffstat (limited to 'target/linux/ipq806x')
14 files changed, 0 insertions, 2244 deletions
diff --git a/target/linux/ipq806x/patches-5.15/100-v5.11-dmaengine-qcom-add_ADM_driver.patch b/target/linux/ipq806x/patches-5.15/100-v5.11-dmaengine-qcom-add_ADM_driver.patch deleted file mode 100644 index 2d24da01e4..0000000000 --- a/target/linux/ipq806x/patches-5.15/100-v5.11-dmaengine-qcom-add_ADM_driver.patch +++ /dev/null @@ -1,965 +0,0 @@ -From 5c9f8c2dbdbe53818bcde6aa6695e1331e5f841f Mon Sep 17 00:00:00 2001 -From: Jonathan McDowell <noodles@earth.li> -Date: Sat, 14 Nov 2020 14:02:33 +0000 -Subject: dmaengine: qcom: Add ADM driver - -Add the DMA engine driver for the QCOM Application Data Mover (ADM) DMA -controller found in the MSM8x60 and IPQ/APQ8064 platforms. - -The ADM supports both memory to memory transactions and memory -to/from peripheral device transactions. The controller also provides -flow control capabilities for transactions to/from peripheral devices. - -The initial release of this driver supports slave transfers to/from -peripherals and also incorporates CRCI (client rate control interface) -flow control. - -The hardware only supports a 32 bit physical address, so specifying -!PHYS_ADDR_T_64BIT gives maximum COMPILE_TEST coverage without having to -spend effort on kludging things in the code that will never actually be -needed on real hardware. - -Signed-off-by: Andy Gross <agross@codeaurora.org> -Signed-off-by: Thomas Pedersen <twp@codeaurora.org> -Signed-off-by: Jonathan McDowell <noodles@earth.li> -Link: https://lore.kernel.org/r/20201114140233.GM32650@earth.li -Signed-off-by: Vinod Koul <vkoul@kernel.org> ---- - drivers/dma/qcom/Kconfig | 11 + - drivers/dma/qcom/Makefile | 1 + - drivers/dma/qcom/qcom_adm.c | 903 ++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 915 insertions(+) - create mode 100644 drivers/dma/qcom/qcom_adm.c - ---- a/drivers/dma/qcom/Kconfig -+++ b/drivers/dma/qcom/Kconfig -@@ -1,4 +1,15 @@ - # SPDX-License-Identifier: GPL-2.0-only -+config QCOM_ADM -+ tristate "Qualcomm ADM support" -+ depends on (ARCH_QCOM || COMPILE_TEST) && !PHYS_ADDR_T_64BIT -+ select DMA_ENGINE -+ select DMA_VIRTUAL_CHANNELS -+ help -+ Enable support for the Qualcomm Application Data Mover (ADM) DMA -+ controller, as present on MSM8x60, APQ8064, and IPQ8064 devices. -+ This controller provides DMA capabilities for both general purpose -+ and on-chip peripheral devices. -+ - config QCOM_BAM_DMA - tristate "QCOM BAM DMA support" - depends on ARCH_QCOM || (COMPILE_TEST && OF && ARM) ---- a/drivers/dma/qcom/Makefile -+++ b/drivers/dma/qcom/Makefile -@@ -1,4 +1,5 @@ - # SPDX-License-Identifier: GPL-2.0 -+obj-$(CONFIG_QCOM_ADM) += qcom_adm.o - obj-$(CONFIG_QCOM_BAM_DMA) += bam_dma.o - obj-$(CONFIG_QCOM_HIDMA_MGMT) += hdma_mgmt.o - hdma_mgmt-objs := hidma_mgmt.o hidma_mgmt_sys.o ---- /dev/null -+++ b/drivers/dma/qcom/qcom_adm.c -@@ -0,0 +1,903 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* -+ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. -+ */ -+ -+#include <linux/clk.h> -+#include <linux/delay.h> -+#include <linux/device.h> -+#include <linux/dmaengine.h> -+#include <linux/dma-mapping.h> -+#include <linux/init.h> -+#include <linux/interrupt.h> -+#include <linux/io.h> -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/of.h> -+#include <linux/of_address.h> -+#include <linux/of_irq.h> -+#include <linux/of_dma.h> -+#include <linux/platform_device.h> -+#include <linux/reset.h> -+#include <linux/scatterlist.h> -+#include <linux/slab.h> -+ -+#include "../dmaengine.h" -+#include "../virt-dma.h" -+ -+/* ADM registers - calculated from channel number and security domain */ -+#define ADM_CHAN_MULTI 0x4 -+#define ADM_CI_MULTI 0x4 -+#define ADM_CRCI_MULTI 0x4 -+#define ADM_EE_MULTI 0x800 -+#define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * (chan)) -+#define ADM_EE_OFFS(ee) (ADM_EE_MULTI * (ee)) -+#define ADM_CHAN_EE_OFFS(chan, ee) (ADM_CHAN_OFFS(chan) + ADM_EE_OFFS(ee)) -+#define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * (chan)) -+#define ADM_CI_OFFS(ci) (ADM_CHAN_OFF(ci)) -+#define ADM_CH_CMD_PTR(chan, ee) (ADM_CHAN_EE_OFFS(chan, ee)) -+#define ADM_CH_RSLT(chan, ee) (0x40 + ADM_CHAN_EE_OFFS(chan, ee)) -+#define ADM_CH_FLUSH_STATE0(chan, ee) (0x80 + ADM_CHAN_EE_OFFS(chan, ee)) -+#define ADM_CH_STATUS_SD(chan, ee) (0x200 + ADM_CHAN_EE_OFFS(chan, ee)) -+#define ADM_CH_CONF(chan) (0x240 + ADM_CHAN_OFFS(chan)) -+#define ADM_CH_RSLT_CONF(chan, ee) (0x300 + ADM_CHAN_EE_OFFS(chan, ee)) -+#define ADM_SEC_DOMAIN_IRQ_STATUS(ee) (0x380 + ADM_EE_OFFS(ee)) -+#define ADM_CI_CONF(ci) (0x390 + (ci) * ADM_CI_MULTI) -+#define ADM_GP_CTL 0x3d8 -+#define ADM_CRCI_CTL(crci, ee) (0x400 + (crci) * ADM_CRCI_MULTI + \ -+ ADM_EE_OFFS(ee)) -+ -+/* channel status */ -+#define ADM_CH_STATUS_VALID BIT(1) -+ -+/* channel result */ -+#define ADM_CH_RSLT_VALID BIT(31) -+#define ADM_CH_RSLT_ERR BIT(3) -+#define ADM_CH_RSLT_FLUSH BIT(2) -+#define ADM_CH_RSLT_TPD BIT(1) -+ -+/* channel conf */ -+#define ADM_CH_CONF_SHADOW_EN BIT(12) -+#define ADM_CH_CONF_MPU_DISABLE BIT(11) -+#define ADM_CH_CONF_PERM_MPU_CONF BIT(9) -+#define ADM_CH_CONF_FORCE_RSLT_EN BIT(7) -+#define ADM_CH_CONF_SEC_DOMAIN(ee) ((((ee) & 0x3) << 4) | (((ee) & 0x4) << 11)) -+ -+/* channel result conf */ -+#define ADM_CH_RSLT_CONF_FLUSH_EN BIT(1) -+#define ADM_CH_RSLT_CONF_IRQ_EN BIT(0) -+ -+/* CRCI CTL */ -+#define ADM_CRCI_CTL_MUX_SEL BIT(18) -+#define ADM_CRCI_CTL_RST BIT(17) -+ -+/* CI configuration */ -+#define ADM_CI_RANGE_END(x) ((x) << 24) -+#define ADM_CI_RANGE_START(x) ((x) << 16) -+#define ADM_CI_BURST_4_WORDS BIT(2) -+#define ADM_CI_BURST_8_WORDS BIT(3) -+ -+/* GP CTL */ -+#define ADM_GP_CTL_LP_EN BIT(12) -+#define ADM_GP_CTL_LP_CNT(x) ((x) << 8) -+ -+/* Command pointer list entry */ -+#define ADM_CPLE_LP BIT(31) -+#define ADM_CPLE_CMD_PTR_LIST BIT(29) -+ -+/* Command list entry */ -+#define ADM_CMD_LC BIT(31) -+#define ADM_CMD_DST_CRCI(n) (((n) & 0xf) << 7) -+#define ADM_CMD_SRC_CRCI(n) (((n) & 0xf) << 3) -+ -+#define ADM_CMD_TYPE_SINGLE 0x0 -+#define ADM_CMD_TYPE_BOX 0x3 -+ -+#define ADM_CRCI_MUX_SEL BIT(4) -+#define ADM_DESC_ALIGN 8 -+#define ADM_MAX_XFER (SZ_64K - 1) -+#define ADM_MAX_ROWS (SZ_64K - 1) -+#define ADM_MAX_CHANNELS 16 -+ -+struct adm_desc_hw_box { -+ u32 cmd; -+ u32 src_addr; -+ u32 dst_addr; -+ u32 row_len; -+ u32 num_rows; -+ u32 row_offset; -+}; -+ -+struct adm_desc_hw_single { -+ u32 cmd; -+ u32 src_addr; -+ u32 dst_addr; -+ u32 len; -+}; -+ -+struct adm_async_desc { -+ struct virt_dma_desc vd; -+ struct adm_device *adev; -+ -+ size_t length; -+ enum dma_transfer_direction dir; -+ dma_addr_t dma_addr; -+ size_t dma_len; -+ -+ void *cpl; -+ dma_addr_t cp_addr; -+ u32 crci; -+ u32 mux; -+ u32 blk_size; -+}; -+ -+struct adm_chan { -+ struct virt_dma_chan vc; -+ struct adm_device *adev; -+ -+ /* parsed from DT */ -+ u32 id; /* channel id */ -+ -+ struct adm_async_desc *curr_txd; -+ struct dma_slave_config slave; -+ struct list_head node; -+ -+ int error; -+ int initialized; -+}; -+ -+static inline struct adm_chan *to_adm_chan(struct dma_chan *common) -+{ -+ return container_of(common, struct adm_chan, vc.chan); -+} -+ -+struct adm_device { -+ void __iomem *regs; -+ struct device *dev; -+ struct dma_device common; -+ struct device_dma_parameters dma_parms; -+ struct adm_chan *channels; -+ -+ u32 ee; -+ -+ struct clk *core_clk; -+ struct clk *iface_clk; -+ -+ struct reset_control *clk_reset; -+ struct reset_control *c0_reset; -+ struct reset_control *c1_reset; -+ struct reset_control *c2_reset; -+ int irq; -+}; -+ -+/** -+ * adm_free_chan - Frees dma resources associated with the specific channel -+ * -+ * Free all allocated descriptors associated with this channel -+ * -+ */ -+static void adm_free_chan(struct dma_chan *chan) -+{ -+ /* free all queued descriptors */ -+ vchan_free_chan_resources(to_virt_chan(chan)); -+} -+ -+/** -+ * adm_get_blksize - Get block size from burst value -+ * -+ */ -+static int adm_get_blksize(unsigned int burst) -+{ -+ int ret; -+ -+ switch (burst) { -+ case 16: -+ case 32: -+ case 64: -+ case 128: -+ ret = ffs(burst >> 4) - 1; -+ break; -+ case 192: -+ ret = 4; -+ break; -+ case 256: -+ ret = 5; -+ break; -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ -+ return ret; -+} -+ -+/** -+ * adm_process_fc_descriptors - Process descriptors for flow controlled xfers -+ * -+ * @achan: ADM channel -+ * @desc: Descriptor memory pointer -+ * @sg: Scatterlist entry -+ * @crci: CRCI value -+ * @burst: Burst size of transaction -+ * @direction: DMA transfer direction -+ */ -+static void *adm_process_fc_descriptors(struct adm_chan *achan, void *desc, -+ struct scatterlist *sg, u32 crci, -+ u32 burst, -+ enum dma_transfer_direction direction) -+{ -+ struct adm_desc_hw_box *box_desc = NULL; -+ struct adm_desc_hw_single *single_desc; -+ u32 remainder = sg_dma_len(sg); -+ u32 rows, row_offset, crci_cmd; -+ u32 mem_addr = sg_dma_address(sg); -+ u32 *incr_addr = &mem_addr; -+ u32 *src, *dst; -+ -+ if (direction == DMA_DEV_TO_MEM) { -+ crci_cmd = ADM_CMD_SRC_CRCI(crci); -+ row_offset = burst; -+ src = &achan->slave.src_addr; -+ dst = &mem_addr; -+ } else { -+ crci_cmd = ADM_CMD_DST_CRCI(crci); -+ row_offset = burst << 16; -+ src = &mem_addr; -+ dst = &achan->slave.dst_addr; -+ } -+ -+ while (remainder >= burst) { -+ box_desc = desc; -+ box_desc->cmd = ADM_CMD_TYPE_BOX | crci_cmd; -+ box_desc->row_offset = row_offset; -+ box_desc->src_addr = *src; -+ box_desc->dst_addr = *dst; -+ -+ rows = remainder / burst; -+ rows = min_t(u32, rows, ADM_MAX_ROWS); -+ box_desc->num_rows = rows << 16 | rows; -+ box_desc->row_len = burst << 16 | burst; -+ -+ *incr_addr += burst * rows; -+ remainder -= burst * rows; -+ desc += sizeof(*box_desc); -+ } -+ -+ /* if leftover bytes, do one single descriptor */ -+ if (remainder) { -+ single_desc = desc; -+ single_desc->cmd = ADM_CMD_TYPE_SINGLE | crci_cmd; -+ single_desc->len = remainder; -+ single_desc->src_addr = *src; -+ single_desc->dst_addr = *dst; -+ desc += sizeof(*single_desc); -+ -+ if (sg_is_last(sg)) -+ single_desc->cmd |= ADM_CMD_LC; -+ } else { -+ if (box_desc && sg_is_last(sg)) -+ box_desc->cmd |= ADM_CMD_LC; -+ } -+ -+ return desc; -+} -+ -+/** -+ * adm_process_non_fc_descriptors - Process descriptors for non-fc xfers -+ * -+ * @achan: ADM channel -+ * @desc: Descriptor memory pointer -+ * @sg: Scatterlist entry -+ * @direction: DMA transfer direction -+ */ -+static void *adm_process_non_fc_descriptors(struct adm_chan *achan, void *desc, -+ struct scatterlist *sg, -+ enum dma_transfer_direction direction) -+{ -+ struct adm_desc_hw_single *single_desc; -+ u32 remainder = sg_dma_len(sg); -+ u32 mem_addr = sg_dma_address(sg); -+ u32 *incr_addr = &mem_addr; -+ u32 *src, *dst; -+ -+ if (direction == DMA_DEV_TO_MEM) { -+ src = &achan->slave.src_addr; -+ dst = &mem_addr; -+ } else { -+ src = &mem_addr; -+ dst = &achan->slave.dst_addr; -+ } -+ -+ do { -+ single_desc = desc; -+ single_desc->cmd = ADM_CMD_TYPE_SINGLE; -+ single_desc->src_addr = *src; -+ single_desc->dst_addr = *dst; -+ single_desc->len = (remainder > ADM_MAX_XFER) ? -+ ADM_MAX_XFER : remainder; -+ -+ remainder -= single_desc->len; -+ *incr_addr += single_desc->len; -+ desc += sizeof(*single_desc); -+ } while (remainder); -+ -+ /* set last command if this is the end of the whole transaction */ -+ if (sg_is_last(sg)) -+ single_desc->cmd |= ADM_CMD_LC; -+ -+ return desc; -+} -+ -+/** -+ * adm_prep_slave_sg - Prep slave sg transaction -+ * -+ * @chan: dma channel -+ * @sgl: scatter gather list -+ * @sg_len: length of sg -+ * @direction: DMA transfer direction -+ * @flags: DMA flags -+ * @context: transfer context (unused) -+ */ -+static struct dma_async_tx_descriptor *adm_prep_slave_sg(struct dma_chan *chan, -+ struct scatterlist *sgl, -+ unsigned int sg_len, -+ enum dma_transfer_direction direction, -+ unsigned long flags, -+ void *context) -+{ -+ struct adm_chan *achan = to_adm_chan(chan); -+ struct adm_device *adev = achan->adev; -+ struct adm_async_desc *async_desc; -+ struct scatterlist *sg; -+ dma_addr_t cple_addr; -+ u32 i, burst; -+ u32 single_count = 0, box_count = 0, crci = 0; -+ void *desc; -+ u32 *cple; -+ int blk_size = 0; -+ -+ if (!is_slave_direction(direction)) { -+ dev_err(adev->dev, "invalid dma direction\n"); -+ return NULL; -+ } -+ -+ /* -+ * get burst value from slave configuration -+ */ -+ burst = (direction == DMA_MEM_TO_DEV) ? -+ achan->slave.dst_maxburst : -+ achan->slave.src_maxburst; -+ -+ /* if using flow control, validate burst and crci values */ -+ if (achan->slave.device_fc) { -+ blk_size = adm_get_blksize(burst); -+ if (blk_size < 0) { -+ dev_err(adev->dev, "invalid burst value: %d\n", -+ burst); -+ return ERR_PTR(-EINVAL); -+ } -+ -+ crci = achan->slave.slave_id & 0xf; -+ if (!crci || achan->slave.slave_id > 0x1f) { -+ dev_err(adev->dev, "invalid crci value\n"); -+ return ERR_PTR(-EINVAL); -+ } -+ } -+ -+ /* iterate through sgs and compute allocation size of structures */ -+ for_each_sg(sgl, sg, sg_len, i) { -+ if (achan->slave.device_fc) { -+ box_count += DIV_ROUND_UP(sg_dma_len(sg) / burst, -+ ADM_MAX_ROWS); -+ if (sg_dma_len(sg) % burst) -+ single_count++; -+ } else { -+ single_count += DIV_ROUND_UP(sg_dma_len(sg), -+ ADM_MAX_XFER); -+ } -+ } -+ -+ async_desc = kzalloc(sizeof(*async_desc), GFP_NOWAIT); -+ if (!async_desc) -+ return ERR_PTR(-ENOMEM); -+ -+ if (crci) -+ async_desc->mux = achan->slave.slave_id & ADM_CRCI_MUX_SEL ? -+ ADM_CRCI_CTL_MUX_SEL : 0; -+ async_desc->crci = crci; -+ async_desc->blk_size = blk_size; -+ async_desc->dma_len = single_count * sizeof(struct adm_desc_hw_single) + -+ box_count * sizeof(struct adm_desc_hw_box) + -+ sizeof(*cple) + 2 * ADM_DESC_ALIGN; -+ -+ async_desc->cpl = kzalloc(async_desc->dma_len, GFP_NOWAIT); -+ if (!async_desc->cpl) -+ goto free; -+ -+ async_desc->adev = adev; -+ -+ /* both command list entry and descriptors must be 8 byte aligned */ -+ cple = PTR_ALIGN(async_desc->cpl, ADM_DESC_ALIGN); -+ desc = PTR_ALIGN(cple + 1, ADM_DESC_ALIGN); -+ -+ for_each_sg(sgl, sg, sg_len, i) { -+ async_desc->length += sg_dma_len(sg); -+ -+ if (achan->slave.device_fc) -+ desc = adm_process_fc_descriptors(achan, desc, sg, crci, -+ burst, direction); -+ else -+ desc = adm_process_non_fc_descriptors(achan, desc, sg, -+ direction); -+ } -+ -+ async_desc->dma_addr = dma_map_single(adev->dev, async_desc->cpl, -+ async_desc->dma_len, -+ DMA_TO_DEVICE); -+ if (dma_mapping_error(adev->dev, async_desc->dma_addr)) -+ goto free; -+ -+ cple_addr = async_desc->dma_addr + ((void *)cple - async_desc->cpl); -+ -+ /* init cmd list */ -+ dma_sync_single_for_cpu(adev->dev, cple_addr, sizeof(*cple), -+ DMA_TO_DEVICE); -+ *cple = ADM_CPLE_LP; -+ *cple |= (async_desc->dma_addr + ADM_DESC_ALIGN) >> 3; -+ dma_sync_single_for_device(adev->dev, cple_addr, sizeof(*cple), -+ DMA_TO_DEVICE); -+ -+ return vchan_tx_prep(&achan->vc, &async_desc->vd, flags); -+ -+free: -+ kfree(async_desc); -+ return ERR_PTR(-ENOMEM); -+} -+ -+/** -+ * adm_terminate_all - terminate all transactions on a channel -+ * @achan: adm dma channel -+ * -+ * Dequeues and frees all transactions, aborts current transaction -+ * No callbacks are done -+ * -+ */ -+static int adm_terminate_all(struct dma_chan *chan) -+{ -+ struct adm_chan *achan = to_adm_chan(chan); -+ struct adm_device *adev = achan->adev; -+ unsigned long flags; -+ LIST_HEAD(head); -+ -+ spin_lock_irqsave(&achan->vc.lock, flags); -+ vchan_get_all_descriptors(&achan->vc, &head); -+ -+ /* send flush command to terminate current transaction */ -+ writel_relaxed(0x0, -+ adev->regs + ADM_CH_FLUSH_STATE0(achan->id, adev->ee)); -+ -+ spin_unlock_irqrestore(&achan->vc.lock, flags); -+ -+ vchan_dma_desc_free_list(&achan->vc, &head); -+ -+ return 0; -+} -+ -+static int adm_slave_config(struct dma_chan *chan, struct dma_slave_config *cfg) -+{ -+ struct adm_chan *achan = to_adm_chan(chan); -+ unsigned long flag; -+ -+ spin_lock_irqsave(&achan->vc.lock, flag); -+ memcpy(&achan->slave, cfg, sizeof(struct dma_slave_config)); -+ spin_unlock_irqrestore(&achan->vc.lock, flag); -+ -+ return 0; -+} -+ -+/** -+ * adm_start_dma - start next transaction -+ * @achan - ADM dma channel -+ */ -+static void adm_start_dma(struct adm_chan *achan) -+{ -+ struct virt_dma_desc *vd = vchan_next_desc(&achan->vc); -+ struct adm_device *adev = achan->adev; -+ struct adm_async_desc *async_desc; -+ -+ lockdep_assert_held(&achan->vc.lock); -+ -+ if (!vd) -+ return; -+ -+ list_del(&vd->node); -+ -+ /* write next command list out to the CMD FIFO */ -+ async_desc = container_of(vd, struct adm_async_desc, vd); -+ achan->curr_txd = async_desc; -+ -+ /* reset channel error */ -+ achan->error = 0; -+ -+ if (!achan->initialized) { -+ /* enable interrupts */ -+ writel(ADM_CH_CONF_SHADOW_EN | -+ ADM_CH_CONF_PERM_MPU_CONF | -+ ADM_CH_CONF_MPU_DISABLE | -+ ADM_CH_CONF_SEC_DOMAIN(adev->ee), -+ adev->regs + ADM_CH_CONF(achan->id)); -+ -+ writel(ADM_CH_RSLT_CONF_IRQ_EN | ADM_CH_RSLT_CONF_FLUSH_EN, -+ adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee)); -+ -+ achan->initialized = 1; -+ } -+ -+ /* set the crci block size if this transaction requires CRCI */ -+ if (async_desc->crci) { -+ writel(async_desc->mux | async_desc->blk_size, -+ adev->regs + ADM_CRCI_CTL(async_desc->crci, adev->ee)); -+ } -+ -+ /* make sure IRQ enable doesn't get reordered */ -+ wmb(); -+ -+ /* write next command list out to the CMD FIFO */ -+ writel(ALIGN(async_desc->dma_addr, ADM_DESC_ALIGN) >> 3, -+ adev->regs + ADM_CH_CMD_PTR(achan->id, adev->ee)); -+} -+ -+/** -+ * adm_dma_irq - irq handler for ADM controller -+ * @irq: IRQ of interrupt -+ * @data: callback data -+ * -+ * IRQ handler for the bam controller -+ */ -+static irqreturn_t adm_dma_irq(int irq, void *data) -+{ -+ struct adm_device *adev = data; -+ u32 srcs, i; -+ struct adm_async_desc *async_desc; -+ unsigned long flags; -+ -+ srcs = readl_relaxed(adev->regs + -+ ADM_SEC_DOMAIN_IRQ_STATUS(adev->ee)); -+ -+ for (i = 0; i < ADM_MAX_CHANNELS; i++) { -+ struct adm_chan *achan = &adev->channels[i]; -+ u32 status, result; -+ -+ if (srcs & BIT(i)) { -+ status = readl_relaxed(adev->regs + -+ ADM_CH_STATUS_SD(i, adev->ee)); -+ -+ /* if no result present, skip */ -+ if (!(status & ADM_CH_STATUS_VALID)) -+ continue; -+ -+ result = readl_relaxed(adev->regs + -+ ADM_CH_RSLT(i, adev->ee)); -+ -+ /* no valid results, skip */ -+ if (!(result & ADM_CH_RSLT_VALID)) -+ continue; -+ -+ /* flag error if transaction was flushed or failed */ -+ if (result & (ADM_CH_RSLT_ERR | ADM_CH_RSLT_FLUSH)) -+ achan->error = 1; -+ -+ spin_lock_irqsave(&achan->vc.lock, flags); -+ async_desc = achan->curr_txd; -+ -+ achan->curr_txd = NULL; -+ -+ if (async_desc) { -+ vchan_cookie_complete(&async_desc->vd); -+ -+ /* kick off next DMA */ -+ adm_start_dma(achan); -+ } -+ -+ spin_unlock_irqrestore(&achan->vc.lock, flags); -+ } -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+/** -+ * adm_tx_status - returns status of transaction -+ * @chan: dma channel -+ * @cookie: transaction cookie -+ * @txstate: DMA transaction state -+ * -+ * Return status of dma transaction -+ */ -+static enum dma_status adm_tx_status(struct dma_chan *chan, dma_cookie_t cookie, -+ struct dma_tx_state *txstate) -+{ -+ struct adm_chan *achan = to_adm_chan(chan); -+ struct virt_dma_desc *vd; -+ enum dma_status ret; -+ unsigned long flags; -+ size_t residue = 0; -+ -+ ret = dma_cookie_status(chan, cookie, txstate); -+ if (ret == DMA_COMPLETE || !txstate) -+ return ret; -+ -+ spin_lock_irqsave(&achan->vc.lock, flags); -+ -+ vd = vchan_find_desc(&achan->vc, cookie); -+ if (vd) -+ residue = container_of(vd, struct adm_async_desc, vd)->length; -+ -+ spin_unlock_irqrestore(&achan->vc.lock, flags); -+ -+ /* -+ * residue is either the full length if it is in the issued list, or 0 -+ * if it is in progress. We have no reliable way of determining -+ * anything inbetween -+ */ -+ dma_set_residue(txstate, residue); -+ -+ if (achan->error) -+ return DMA_ERROR; -+ -+ return ret; -+} -+ -+/** -+ * adm_issue_pending - starts pending transactions -+ * @chan: dma channel -+ * -+ * Issues all pending transactions and starts DMA -+ */ -+static void adm_issue_pending(struct dma_chan *chan) -+{ -+ struct adm_chan *achan = to_adm_chan(chan); -+ unsigned long flags; -+ -+ spin_lock_irqsave(&achan->vc.lock, flags); -+ -+ if (vchan_issue_pending(&achan->vc) && !achan->curr_txd) -+ adm_start_dma(achan); -+ spin_unlock_irqrestore(&achan->vc.lock, flags); -+} -+ -+/** -+ * adm_dma_free_desc - free descriptor memory -+ * @vd: virtual descriptor -+ * -+ */ -+static void adm_dma_free_desc(struct virt_dma_desc *vd) -+{ -+ struct adm_async_desc *async_desc = container_of(vd, -+ struct adm_async_desc, vd); -+ -+ dma_unmap_single(async_desc->adev->dev, async_desc->dma_addr, -+ async_desc->dma_len, DMA_TO_DEVICE); -+ kfree(async_desc->cpl); -+ kfree(async_desc); -+} -+ -+static void adm_channel_init(struct adm_device *adev, struct adm_chan *achan, -+ u32 index) -+{ -+ achan->id = index; -+ achan->adev = adev; -+ -+ vchan_init(&achan->vc, &adev->common); -+ achan->vc.desc_free = adm_dma_free_desc; -+} -+ -+static int adm_dma_probe(struct platform_device *pdev) -+{ -+ struct adm_device *adev; -+ int ret; -+ u32 i; -+ -+ adev = devm_kzalloc(&pdev->dev, sizeof(*adev), GFP_KERNEL); -+ if (!adev) -+ return -ENOMEM; -+ -+ adev->dev = &pdev->dev; -+ -+ adev->regs = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(adev->regs)) -+ return PTR_ERR(adev->regs); -+ -+ adev->irq = platform_get_irq(pdev, 0); -+ if (adev->irq < 0) -+ return adev->irq; -+ -+ ret = of_property_read_u32(pdev->dev.of_node, "qcom,ee", &adev->ee); -+ if (ret) { -+ dev_err(adev->dev, "Execution environment unspecified\n"); -+ return ret; -+ } -+ -+ adev->core_clk = devm_clk_get(adev->dev, "core"); -+ if (IS_ERR(adev->core_clk)) -+ return PTR_ERR(adev->core_clk); -+ -+ adev->iface_clk = devm_clk_get(adev->dev, "iface"); -+ if (IS_ERR(adev->iface_clk)) -+ return PTR_ERR(adev->iface_clk); -+ -+ adev->clk_reset = devm_reset_control_get_exclusive(&pdev->dev, "clk"); -+ if (IS_ERR(adev->clk_reset)) { -+ dev_err(adev->dev, "failed to get ADM0 reset\n"); -+ return PTR_ERR(adev->clk_reset); -+ } -+ -+ adev->c0_reset = devm_reset_control_get_exclusive(&pdev->dev, "c0"); -+ if (IS_ERR(adev->c0_reset)) { -+ dev_err(adev->dev, "failed to get ADM0 C0 reset\n"); -+ return PTR_ERR(adev->c0_reset); -+ } -+ -+ adev->c1_reset = devm_reset_control_get_exclusive(&pdev->dev, "c1"); -+ if (IS_ERR(adev->c1_reset)) { -+ dev_err(adev->dev, "failed to get ADM0 C1 reset\n"); -+ return PTR_ERR(adev->c1_reset); -+ } -+ -+ adev->c2_reset = devm_reset_control_get_exclusive(&pdev->dev, "c2"); -+ if (IS_ERR(adev->c2_reset)) { -+ dev_err(adev->dev, "failed to get ADM0 C2 reset\n"); -+ return PTR_ERR(adev->c2_reset); -+ } -+ -+ ret = clk_prepare_enable(adev->core_clk); -+ if (ret) { -+ dev_err(adev->dev, "failed to prepare/enable core clock\n"); -+ return ret; -+ } -+ -+ ret = clk_prepare_enable(adev->iface_clk); -+ if (ret) { -+ dev_err(adev->dev, "failed to prepare/enable iface clock\n"); -+ goto err_disable_core_clk; -+ } -+ -+ reset_control_assert(adev->clk_reset); -+ reset_control_assert(adev->c0_reset); -+ reset_control_assert(adev->c1_reset); -+ reset_control_assert(adev->c2_reset); -+ -+ udelay(2); -+ -+ reset_control_deassert(adev->clk_reset); -+ reset_control_deassert(adev->c0_reset); -+ reset_control_deassert(adev->c1_reset); -+ reset_control_deassert(adev->c2_reset); -+ -+ adev->channels = devm_kcalloc(adev->dev, ADM_MAX_CHANNELS, -+ sizeof(*adev->channels), GFP_KERNEL); -+ -+ if (!adev->channels) { -+ ret = -ENOMEM; -+ goto err_disable_clks; -+ } -+ -+ /* allocate and initialize channels */ -+ INIT_LIST_HEAD(&adev->common.channels); -+ -+ for (i = 0; i < ADM_MAX_CHANNELS; i++) -+ adm_channel_init(adev, &adev->channels[i], i); -+ -+ /* reset CRCIs */ -+ for (i = 0; i < 16; i++) -+ writel(ADM_CRCI_CTL_RST, adev->regs + -+ ADM_CRCI_CTL(i, adev->ee)); -+ -+ /* configure client interfaces */ -+ writel(ADM_CI_RANGE_START(0x40) | ADM_CI_RANGE_END(0xb0) | -+ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(0)); -+ writel(ADM_CI_RANGE_START(0x2a) | ADM_CI_RANGE_END(0x2c) | -+ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(1)); -+ writel(ADM_CI_RANGE_START(0x12) | ADM_CI_RANGE_END(0x28) | -+ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(2)); -+ writel(ADM_GP_CTL_LP_EN | ADM_GP_CTL_LP_CNT(0xf), -+ adev->regs + ADM_GP_CTL); -+ -+ ret = devm_request_irq(adev->dev, adev->irq, adm_dma_irq, -+ 0, "adm_dma", adev); -+ if (ret) -+ goto err_disable_clks; -+ -+ platform_set_drvdata(pdev, adev); -+ -+ adev->common.dev = adev->dev; -+ adev->common.dev->dma_parms = &adev->dma_parms; -+ -+ /* set capabilities */ -+ dma_cap_zero(adev->common.cap_mask); -+ dma_cap_set(DMA_SLAVE, adev->common.cap_mask); -+ dma_cap_set(DMA_PRIVATE, adev->common.cap_mask); -+ -+ /* initialize dmaengine apis */ -+ adev->common.directions = BIT(DMA_DEV_TO_MEM | DMA_MEM_TO_DEV); -+ adev->common.residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR; -+ adev->common.src_addr_widths = DMA_SLAVE_BUSWIDTH_4_BYTES; -+ adev->common.dst_addr_widths = DMA_SLAVE_BUSWIDTH_4_BYTES; -+ adev->common.device_free_chan_resources = adm_free_chan; -+ adev->common.device_prep_slave_sg = adm_prep_slave_sg; -+ adev->common.device_issue_pending = adm_issue_pending; -+ adev->common.device_tx_status = adm_tx_status; -+ adev->common.device_terminate_all = adm_terminate_all; -+ adev->common.device_config = adm_slave_config; -+ -+ ret = dma_async_device_register(&adev->common); -+ if (ret) { -+ dev_err(adev->dev, "failed to register dma async device\n"); -+ goto err_disable_clks; -+ } -+ -+ ret = of_dma_controller_register(pdev->dev.of_node, -+ of_dma_xlate_by_chan_id, -+ &adev->common); -+ if (ret) -+ goto err_unregister_dma; -+ -+ return 0; -+ -+err_unregister_dma: -+ dma_async_device_unregister(&adev->common); -+err_disable_clks: -+ clk_disable_unprepare(adev->iface_clk); -+err_disable_core_clk: -+ clk_disable_unprepare(adev->core_clk); -+ -+ return ret; -+} -+ -+static int adm_dma_remove(struct platform_device *pdev) -+{ -+ struct adm_device *adev = platform_get_drvdata(pdev); -+ struct adm_chan *achan; -+ u32 i; -+ -+ of_dma_controller_free(pdev->dev.of_node); -+ dma_async_device_unregister(&adev->common); -+ -+ for (i = 0; i < ADM_MAX_CHANNELS; i++) { -+ achan = &adev->channels[i]; -+ -+ /* mask IRQs for this channel/EE pair */ -+ writel(0, adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee)); -+ -+ tasklet_kill(&adev->channels[i].vc.task); -+ adm_terminate_all(&adev->channels[i].vc.chan); -+ } -+ -+ devm_free_irq(adev->dev, adev->irq, adev); -+ -+ clk_disable_unprepare(adev->core_clk); -+ clk_disable_unprepare(adev->iface_clk); -+ -+ return 0; -+} -+ -+static const struct of_device_id adm_of_match[] = { -+ { .compatible = "qcom,adm", }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, adm_of_match); -+ -+static struct platform_driver adm_dma_driver = { -+ .probe = adm_dma_probe, -+ .remove = adm_dma_remove, -+ .driver = { -+ .name = "adm-dma-engine", -+ .of_match_table = adm_of_match, -+ }, -+}; -+ -+module_platform_driver(adm_dma_driver); -+ -+MODULE_AUTHOR("Andy Gross <agross@codeaurora.org>"); -+MODULE_DESCRIPTION("QCOM ADM DMA engine driver"); -+MODULE_LICENSE("GPL v2"); diff --git a/target/linux/ipq806x/patches-5.15/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch b/target/linux/ipq806x/patches-5.15/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch deleted file mode 100644 index a78dc82a47..0000000000 --- a/target/linux/ipq806x/patches-5.15/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch +++ /dev/null @@ -1,217 +0,0 @@ -From 803eb124e1a64e42888542c3444bfe6dac412c7f Mon Sep 17 00:00:00 2001 -From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> -Date: Mon, 4 Jan 2021 09:41:35 +0530 -Subject: mtd: parsers: Add Qcom SMEM parser - -NAND based Qualcomm platforms have the partition table populated in the -Shared Memory (SMEM). Hence, add a parser for parsing the partitions -from it. - -Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> -Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> -Link: https://lore.kernel.org/linux-mtd/20210104041137.113075-3-manivannan.sadhasivam@linaro.org ---- - drivers/mtd/parsers/Kconfig | 8 ++ - drivers/mtd/parsers/Makefile | 1 + - drivers/mtd/parsers/qcomsmempart.c | 170 +++++++++++++++++++++++++++++++++++++ - 3 files changed, 179 insertions(+) - create mode 100644 drivers/mtd/parsers/qcomsmempart.c - ---- a/drivers/mtd/parsers/Kconfig -+++ b/drivers/mtd/parsers/Kconfig -@@ -196,6 +196,14 @@ config MTD_REDBOOT_PARTS_READONLY - - endif # MTD_REDBOOT_PARTS - -+config MTD_QCOMSMEM_PARTS -+ tristate "Qualcomm SMEM NAND flash partition parser" -+ depends on MTD_NAND_QCOM || COMPILE_TEST -+ depends on QCOM_SMEM -+ help -+ This provides support for parsing partitions from Shared Memory (SMEM) -+ for NAND flash on Qualcomm platforms. -+ - config MTD_ROUTERBOOT_PARTS - tristate "RouterBoot flash partition parser" - depends on MTD && OF ---- a/drivers/mtd/parsers/Makefile -+++ b/drivers/mtd/parsers/Makefile -@@ -13,4 +13,5 @@ obj-$(CONFIG_MTD_AFS_PARTS) += afs.o - obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o - obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o - obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o -+obj-$(CONFIG_MTD_QCOMSMEM_PARTS) += qcomsmempart.o - obj-$(CONFIG_MTD_ROUTERBOOT_PARTS) += routerbootpart.o ---- /dev/null -+++ b/drivers/mtd/parsers/qcomsmempart.c -@@ -0,0 +1,170 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* -+ * Qualcomm SMEM NAND flash partition parser -+ * -+ * Copyright (C) 2020, Linaro Ltd. -+ */ -+ -+#include <linux/ctype.h> -+#include <linux/module.h> -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/partitions.h> -+#include <linux/slab.h> -+#include <linux/soc/qcom/smem.h> -+ -+#define SMEM_AARM_PARTITION_TABLE 9 -+#define SMEM_APPS 0 -+ -+#define SMEM_FLASH_PART_MAGIC1 0x55ee73aa -+#define SMEM_FLASH_PART_MAGIC2 0xe35ebddb -+#define SMEM_FLASH_PTABLE_V3 3 -+#define SMEM_FLASH_PTABLE_V4 4 -+#define SMEM_FLASH_PTABLE_MAX_PARTS_V3 16 -+#define SMEM_FLASH_PTABLE_MAX_PARTS_V4 48 -+#define SMEM_FLASH_PTABLE_HDR_LEN (4 * sizeof(u32)) -+#define SMEM_FLASH_PTABLE_NAME_SIZE 16 -+ -+/** -+ * struct smem_flash_pentry - SMEM Flash partition entry -+ * @name: Name of the partition -+ * @offset: Offset in blocks -+ * @length: Length of the partition in blocks -+ * @attr: Flags for this partition -+ */ -+struct smem_flash_pentry { -+ char name[SMEM_FLASH_PTABLE_NAME_SIZE]; -+ __le32 offset; -+ __le32 length; -+ u8 attr; -+} __packed __aligned(4); -+ -+/** -+ * struct smem_flash_ptable - SMEM Flash partition table -+ * @magic1: Partition table Magic 1 -+ * @magic2: Partition table Magic 2 -+ * @version: Partition table version -+ * @numparts: Number of partitions in this ptable -+ * @pentry: Flash partition entries belonging to this ptable -+ */ -+struct smem_flash_ptable { -+ __le32 magic1; -+ __le32 magic2; -+ __le32 version; -+ __le32 numparts; -+ struct smem_flash_pentry pentry[SMEM_FLASH_PTABLE_MAX_PARTS_V4]; -+} __packed __aligned(4); -+ -+static int parse_qcomsmem_part(struct mtd_info *mtd, -+ const struct mtd_partition **pparts, -+ struct mtd_part_parser_data *data) -+{ -+ struct smem_flash_pentry *pentry; -+ struct smem_flash_ptable *ptable; -+ size_t len = SMEM_FLASH_PTABLE_HDR_LEN; -+ struct mtd_partition *parts; -+ int ret, i, numparts; -+ char *name, *c; -+ -+ pr_debug("Parsing partition table info from SMEM\n"); -+ ptable = qcom_smem_get(SMEM_APPS, SMEM_AARM_PARTITION_TABLE, &len); -+ if (IS_ERR(ptable)) { -+ pr_err("Error reading partition table header\n"); -+ return PTR_ERR(ptable); -+ } -+ -+ /* Verify ptable magic */ -+ if (le32_to_cpu(ptable->magic1) != SMEM_FLASH_PART_MAGIC1 || -+ le32_to_cpu(ptable->magic2) != SMEM_FLASH_PART_MAGIC2) { -+ pr_err("Partition table magic verification failed\n"); -+ return -EINVAL; -+ } -+ -+ /* Ensure that # of partitions is less than the max we have allocated */ -+ numparts = le32_to_cpu(ptable->numparts); -+ if (numparts > SMEM_FLASH_PTABLE_MAX_PARTS_V4) { -+ pr_err("Partition numbers exceed the max limit\n"); -+ return -EINVAL; -+ } -+ -+ /* Find out length of partition data based on table version */ -+ if (le32_to_cpu(ptable->version) <= SMEM_FLASH_PTABLE_V3) { -+ len = SMEM_FLASH_PTABLE_HDR_LEN + SMEM_FLASH_PTABLE_MAX_PARTS_V3 * -+ sizeof(struct smem_flash_pentry); -+ } else if (le32_to_cpu(ptable->version) == SMEM_FLASH_PTABLE_V4) { -+ len = SMEM_FLASH_PTABLE_HDR_LEN + SMEM_FLASH_PTABLE_MAX_PARTS_V4 * -+ sizeof(struct smem_flash_pentry); -+ } else { -+ pr_err("Unknown ptable version (%d)", le32_to_cpu(ptable->version)); -+ return -EINVAL; -+ } -+ -+ /* -+ * Now that the partition table header has been parsed, verified -+ * and the length of the partition table calculated, read the -+ * complete partition table -+ */ -+ ptable = qcom_smem_get(SMEM_APPS, SMEM_AARM_PARTITION_TABLE, &len); -+ if (IS_ERR_OR_NULL(ptable)) { -+ pr_err("Error reading partition table\n"); -+ return PTR_ERR(ptable); -+ } -+ -+ parts = kcalloc(numparts, sizeof(*parts), GFP_KERNEL); -+ if (!parts) -+ return -ENOMEM; -+ -+ for (i = 0; i < numparts; i++) { -+ pentry = &ptable->pentry[i]; -+ if (pentry->name[0] == '\0') -+ continue; -+ -+ name = kstrdup(pentry->name, GFP_KERNEL); -+ if (!name) { -+ ret = -ENOMEM; -+ goto out_free_parts; -+ } -+ -+ /* Convert name to lower case */ -+ for (c = name; *c != '\0'; c++) -+ *c = tolower(*c); -+ -+ parts[i].name = name; -+ parts[i].offset = le32_to_cpu(pentry->offset) * mtd->erasesize; -+ parts[i].mask_flags = pentry->attr; -+ parts[i].size = le32_to_cpu(pentry->length) * mtd->erasesize; -+ pr_debug("%d: %s offs=0x%08x size=0x%08x attr:0x%08x\n", -+ i, pentry->name, le32_to_cpu(pentry->offset), -+ le32_to_cpu(pentry->length), pentry->attr); -+ } -+ -+ pr_debug("SMEM partition table found: ver: %d len: %d\n", -+ le32_to_cpu(ptable->version), numparts); -+ *pparts = parts; -+ -+ return numparts; -+ -+out_free_parts: -+ while (--i >= 0) -+ kfree(parts[i].name); -+ kfree(parts); -+ *pparts = NULL; -+ -+ return ret; -+} -+ -+static const struct of_device_id qcomsmem_of_match_table[] = { -+ { .compatible = "qcom,smem-part" }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, qcomsmem_of_match_table); -+ -+static struct mtd_part_parser mtd_parser_qcomsmem = { -+ .parse_fn = parse_qcomsmem_part, -+ .name = "qcomsmem", -+ .of_match_table = qcomsmem_of_match_table, -+}; -+module_mtd_part_parser(mtd_parser_qcomsmem); -+ -+MODULE_LICENSE("GPL v2"); -+MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>"); -+MODULE_DESCRIPTION("Qualcomm SMEM NAND flash partition parser"); diff --git a/target/linux/ipq806x/patches-5.15/104-1-drivers-thermal-tsens-Add-VER_0-tsens-version.patch b/target/linux/ipq806x/patches-5.15/104-1-drivers-thermal-tsens-Add-VER_0-tsens-version.patch deleted file mode 100644 index 8627244c59..0000000000 --- a/target/linux/ipq806x/patches-5.15/104-1-drivers-thermal-tsens-Add-VER_0-tsens-version.patch +++ /dev/null @@ -1,285 +0,0 @@ -From 5c7d1181056feef0b58fb2f556f55e170ba5b479 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith <ansuelsmth@gmail.com> -Date: Sat, 25 Jul 2020 19:14:59 +0200 -Subject: [PATCH 01/10] drivers: thermal: tsens: Add VER_0 tsens version - -VER_0 is used to describe device based on tsens version before v0.1. -These device are devices based on msm8960 for example apq8064 or -ipq806x. - -Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com> -Reviewed-by: Thara Gopinath <thara.gopinath@linaro.org> -Reported-by: kernel test robot <lkp@intel.com> -Reported-by: Dan Carpenter <dan.carpenter@oracle.com> ---- - drivers/thermal/qcom/tsens.c | 150 ++++++++++++++++++++++++++++------- - drivers/thermal/qcom/tsens.h | 4 +- - 2 files changed, 124 insertions(+), 30 deletions(-) - ---- a/drivers/thermal/qcom/tsens.c -+++ b/drivers/thermal/qcom/tsens.c -@@ -12,6 +12,7 @@ - #include <linux/of.h> - #include <linux/of_address.h> - #include <linux/of_platform.h> -+#include <linux/mfd/syscon.h> - #include <linux/platform_device.h> - #include <linux/pm.h> - #include <linux/regmap.h> -@@ -515,6 +516,15 @@ static irqreturn_t tsens_irq_thread(int - dev_dbg(priv->dev, "[%u] %s: no violation: %d\n", - hw_id, __func__, temp); - } -+ -+ if (tsens_version(priv) < VER_0_1) { -+ /* Constraint: There is only 1 interrupt control register for all -+ * 11 temperature sensor. So monitoring more than 1 sensor based -+ * on interrupts will yield inconsistent result. To overcome this -+ * issue we will monitor only sensor 0 which is the master sensor. -+ */ -+ break; -+ } - } - - return IRQ_HANDLED; -@@ -530,6 +540,13 @@ static int tsens_set_trips(void *_sensor - int high_val, low_val, cl_high, cl_low; - u32 hw_id = s->hw_id; - -+ if (tsens_version(priv) < VER_0_1) { -+ /* Pre v0.1 IP had a single register for each type of interrupt -+ * and thresholds -+ */ -+ hw_id = 0; -+ } -+ - dev_dbg(dev, "[%u] %s: proposed thresholds: (%d:%d)\n", - hw_id, __func__, low, high); - -@@ -584,18 +601,21 @@ int get_temp_tsens_valid(const struct ts - u32 valid; - int ret; - -- ret = regmap_field_read(priv->rf[valid_idx], &valid); -- if (ret) -- return ret; -- while (!valid) { -- /* Valid bit is 0 for 6 AHB clock cycles. -- * At 19.2MHz, 1 AHB clock is ~60ns. -- * We should enter this loop very, very rarely. -- */ -- ndelay(400); -+ /* VER_0 doesn't have VALID bit */ -+ if (tsens_version(priv) >= VER_0_1) { - ret = regmap_field_read(priv->rf[valid_idx], &valid); - if (ret) - return ret; -+ while (!valid) { -+ /* Valid bit is 0 for 6 AHB clock cycles. -+ * At 19.2MHz, 1 AHB clock is ~60ns. -+ * We should enter this loop very, very rarely. -+ */ -+ ndelay(400); -+ ret = regmap_field_read(priv->rf[valid_idx], &valid); -+ if (ret) -+ return ret; -+ } - } - - /* Valid bit is set, OK to read the temperature */ -@@ -608,15 +628,29 @@ int get_temp_common(const struct tsens_s - { - struct tsens_priv *priv = s->priv; - int hw_id = s->hw_id; -- int last_temp = 0, ret; -+ int last_temp = 0, ret, trdy; -+ unsigned long timeout; - -- ret = regmap_field_read(priv->rf[LAST_TEMP_0 + hw_id], &last_temp); -- if (ret) -- return ret; -+ timeout = jiffies + usecs_to_jiffies(TIMEOUT_US); -+ do { -+ if (tsens_version(priv) == VER_0) { -+ ret = regmap_field_read(priv->rf[TRDY], &trdy); -+ if (ret) -+ return ret; -+ if (!trdy) -+ continue; -+ } - -- *temp = code_to_degc(last_temp, s) * 1000; -+ ret = regmap_field_read(priv->rf[LAST_TEMP_0 + hw_id], &last_temp); -+ if (ret) -+ return ret; - -- return 0; -+ *temp = code_to_degc(last_temp, s) * 1000; -+ -+ return 0; -+ } while (time_before(jiffies, timeout)); -+ -+ return -ETIMEDOUT; - } - - #ifdef CONFIG_DEBUG_FS -@@ -738,19 +772,34 @@ int __init init_common(struct tsens_priv - priv->tm_offset = 0x1000; - } - -- res = platform_get_resource(op, IORESOURCE_MEM, 0); -- tm_base = devm_ioremap_resource(dev, res); -- if (IS_ERR(tm_base)) { -- ret = PTR_ERR(tm_base); -- goto err_put_device; -+ if (tsens_version(priv) >= VER_0_1) { -+ res = platform_get_resource(op, IORESOURCE_MEM, 0); -+ tm_base = devm_ioremap_resource(dev, res); -+ if (IS_ERR(tm_base)) { -+ ret = PTR_ERR(tm_base); -+ goto err_put_device; -+ } -+ -+ priv->tm_map = devm_regmap_init_mmio(dev, tm_base, &tsens_config); -+ } else { /* VER_0 share the same gcc regs using a syscon */ -+ struct device *parent = priv->dev->parent; -+ -+ if (parent) -+ priv->tm_map = syscon_node_to_regmap(parent->of_node); - } - -- priv->tm_map = devm_regmap_init_mmio(dev, tm_base, &tsens_config); -- if (IS_ERR(priv->tm_map)) { -- ret = PTR_ERR(priv->tm_map); -+ if (IS_ERR_OR_NULL(priv->tm_map)) { -+ if (!priv->tm_map) -+ ret = -ENODEV; -+ else -+ ret = PTR_ERR(priv->tm_map); - goto err_put_device; - } - -+ /* VER_0 have only tm_map */ -+ if (!priv->srot_map) -+ priv->srot_map = priv->tm_map; -+ - if (tsens_version(priv) > VER_0_1) { - for (i = VER_MAJOR; i <= VER_STEP; i++) { - priv->rf[i] = devm_regmap_field_alloc(dev, priv->srot_map, -@@ -771,6 +820,10 @@ int __init init_common(struct tsens_priv - ret = PTR_ERR(priv->rf[TSENS_EN]); - goto err_put_device; - } -+ /* in VER_0 TSENS need to be explicitly enabled */ -+ if (tsens_version(priv) == VER_0) -+ regmap_field_write(priv->rf[TSENS_EN], 1); -+ - ret = regmap_field_read(priv->rf[TSENS_EN], &enabled); - if (ret) - goto err_put_device; -@@ -793,6 +846,19 @@ int __init init_common(struct tsens_priv - goto err_put_device; - } - -+ priv->rf[TSENS_SW_RST] = -+ devm_regmap_field_alloc(dev, priv->srot_map, priv->fields[TSENS_SW_RST]); -+ if (IS_ERR(priv->rf[TSENS_SW_RST])) { -+ ret = PTR_ERR(priv->rf[TSENS_SW_RST]); -+ goto err_put_device; -+ } -+ -+ priv->rf[TRDY] = devm_regmap_field_alloc(dev, priv->tm_map, priv->fields[TRDY]); -+ if (IS_ERR(priv->rf[TRDY])) { -+ ret = PTR_ERR(priv->rf[TRDY]); -+ goto err_put_device; -+ } -+ - /* This loop might need changes if enum regfield_ids is reordered */ - for (j = LAST_TEMP_0; j <= UP_THRESH_15; j += 16) { - for (i = 0; i < priv->feat->max_sensors; i++) { -@@ -808,7 +874,7 @@ int __init init_common(struct tsens_priv - } - } - -- if (priv->feat->crit_int) { -+ if (priv->feat->crit_int || tsens_version(priv) < VER_0_1) { - /* Loop might need changes if enum regfield_ids is reordered */ - for (j = CRITICAL_STATUS_0; j <= CRIT_THRESH_15; j += 16) { - for (i = 0; i < priv->feat->max_sensors; i++) { -@@ -846,7 +912,11 @@ int __init init_common(struct tsens_priv - } - - spin_lock_init(&priv->ul_lock); -- tsens_enable_irq(priv); -+ -+ /* VER_0 interrupt doesn't need to be enabled */ -+ if (tsens_version(priv) >= VER_0_1) -+ tsens_enable_irq(priv); -+ - tsens_debug_init(op); - - err_put_device: -@@ -945,10 +1015,19 @@ static int tsens_register_irq(struct tse - if (irq == -ENXIO) - ret = 0; - } else { -- ret = devm_request_threaded_irq(&pdev->dev, irq, -- NULL, thread_fn, -- IRQF_ONESHOT, -- dev_name(&pdev->dev), priv); -+ /* VER_0 interrupt is TRIGGER_RISING, VER_0_1 and up is ONESHOT */ -+ if (tsens_version(priv) == VER_0) -+ ret = devm_request_threaded_irq(&pdev->dev, irq, -+ thread_fn, NULL, -+ IRQF_TRIGGER_RISING, -+ dev_name(&pdev->dev), -+ priv); -+ else -+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, -+ thread_fn, IRQF_ONESHOT, -+ dev_name(&pdev->dev), -+ priv); -+ - if (ret) - dev_err(&pdev->dev, "%s: failed to get irq\n", - __func__); -@@ -977,6 +1056,19 @@ static int tsens_register(struct tsens_p - priv->ops->enable(priv, i); - } - -+ /* VER_0 require to set MIN and MAX THRESH -+ * These 2 regs are set using the: -+ * - CRIT_THRESH_0 for MAX THRESH hardcoded to 120°C -+ * - CRIT_THRESH_1 for MIN THRESH hardcoded to 0°C -+ */ -+ if (tsens_version(priv) < VER_0_1) { -+ regmap_field_write(priv->rf[CRIT_THRESH_0], -+ tsens_mC_to_hw(priv->sensor, 120000)); -+ -+ regmap_field_write(priv->rf[CRIT_THRESH_1], -+ tsens_mC_to_hw(priv->sensor, 0)); -+ } -+ - ret = tsens_register_irq(priv, "uplow", tsens_irq_thread); - if (ret < 0) - return ret; ---- a/drivers/thermal/qcom/tsens.h -+++ b/drivers/thermal/qcom/tsens.h -@@ -13,6 +13,7 @@ - #define CAL_DEGC_PT2 120 - #define SLOPE_FACTOR 1000 - #define SLOPE_DEFAULT 3200 -+#define TIMEOUT_US 100 - #define THRESHOLD_MAX_ADC_CODE 0x3ff - #define THRESHOLD_MIN_ADC_CODE 0x0 - -@@ -25,7 +26,8 @@ struct tsens_priv; - - /* IP version numbers in ascending order */ - enum tsens_ver { -- VER_0_1 = 0, -+ VER_0 = 0, -+ VER_0_1, - VER_1_X, - VER_2_X, - }; diff --git a/target/linux/ipq806x/patches-5.15/104-2-drivers-thermal-tsens-Don-t-hardcode-sensor-slope.patch b/target/linux/ipq806x/patches-5.15/104-2-drivers-thermal-tsens-Don-t-hardcode-sensor-slope.patch deleted file mode 100644 index 109f524bbd..0000000000 --- a/target/linux/ipq806x/patches-5.15/104-2-drivers-thermal-tsens-Don-t-hardcode-sensor-slope.patch +++ /dev/null @@ -1,28 +0,0 @@ -From efa0d50a6c5ec7619371dfe4d3e6ca54b73787d5 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith <ansuelsmth@gmail.com> -Date: Wed, 25 Nov 2020 16:47:21 +0100 -Subject: [PATCH 02/10] drivers: thermal: tsens: Don't hardcode sensor slope - -Function compute_intercept_slope hardcode the sensor slope to -SLOPE_DEFAULT. Change this and use the default value only if a slope is -not defined. This is needed for tsens VER_0 that has a hardcoded slope -table. - -Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com> -Reviewed-by: Thara Gopinath <thara.gopinath@linaro.org> ---- - drivers/thermal/qcom/tsens.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - ---- a/drivers/thermal/qcom/tsens.c -+++ b/drivers/thermal/qcom/tsens.c -@@ -86,7 +86,8 @@ void compute_intercept_slope(struct tsen - "%s: sensor%d - data_point1:%#x data_point2:%#x\n", - __func__, i, p1[i], p2[i]); - -- priv->sensor[i].slope = SLOPE_DEFAULT; -+ if (!priv->sensor[i].slope) -+ priv->sensor[i].slope = SLOPE_DEFAULT; - if (mode == TWO_PT_CALIB) { - /* - * slope (m) = adc_code2 - adc_code1 (y2 - y1)/ diff --git a/target/linux/ipq806x/patches-5.15/104-3-drivers-thermal-tsens-Convert-msm8960-to-reg_field.patch b/target/linux/ipq806x/patches-5.15/104-3-drivers-thermal-tsens-Convert-msm8960-to-reg_field.patch deleted file mode 100644 index bf378107c6..0000000000 --- a/target/linux/ipq806x/patches-5.15/104-3-drivers-thermal-tsens-Convert-msm8960-to-reg_field.patch +++ /dev/null @@ -1,119 +0,0 @@ -From 6bac2e2fa36c2d7c304768a689d8b73155b90aa2 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith <ansuelsmth@gmail.com> -Date: Wed, 25 Nov 2020 17:15:51 +0100 -Subject: [PATCH 03/10] drivers: thermal: tsens: Convert msm8960 to reg_field - -Convert msm9860 driver to reg_field to use the init_common -function. - -Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com> -Acked-by: Thara Gopinath <thara.gopinath@linaro.org> ---- - drivers/thermal/qcom/tsens-8960.c | 80 ++++++++++++++++++++++++++++++- - 1 file changed, 79 insertions(+), 1 deletion(-) - ---- a/drivers/thermal/qcom/tsens-8960.c -+++ b/drivers/thermal/qcom/tsens-8960.c -@@ -51,11 +51,22 @@ - #define MIN_LIMIT_TH 0x0 - #define MAX_LIMIT_TH 0xff - --#define S0_STATUS_ADDR 0x3628 - #define INT_STATUS_ADDR 0x363c - #define TRDY_MASK BIT(7) - #define TIMEOUT_US 100 - -+#define S0_STATUS_OFF 0x3628 -+#define S1_STATUS_OFF 0x362c -+#define S2_STATUS_OFF 0x3630 -+#define S3_STATUS_OFF 0x3634 -+#define S4_STATUS_OFF 0x3638 -+#define S5_STATUS_OFF 0x3664 /* Sensors 5-10 found on apq8064/msm8960 */ -+#define S6_STATUS_OFF 0x3668 -+#define S7_STATUS_OFF 0x366c -+#define S8_STATUS_OFF 0x3670 -+#define S9_STATUS_OFF 0x3674 -+#define S10_STATUS_OFF 0x3678 -+ - static int suspend_8960(struct tsens_priv *priv) - { - int ret; -@@ -269,6 +280,71 @@ static int get_temp_8960(const struct ts - return -ETIMEDOUT; - } - -+static struct tsens_features tsens_8960_feat = { -+ .ver_major = VER_0, -+ .crit_int = 0, -+ .adc = 1, -+ .srot_split = 0, -+ .max_sensors = 11, -+}; -+ -+static const struct reg_field tsens_8960_regfields[MAX_REGFIELDS] = { -+ /* ----- SROT ------ */ -+ /* No VERSION information */ -+ -+ /* CNTL */ -+ [TSENS_EN] = REG_FIELD(CNTL_ADDR, 0, 0), -+ [TSENS_SW_RST] = REG_FIELD(CNTL_ADDR, 1, 1), -+ /* 8960 has 5 sensors, 8660 has 11, we only handle 5 */ -+ [SENSOR_EN] = REG_FIELD(CNTL_ADDR, 3, 7), -+ -+ /* ----- TM ------ */ -+ /* INTERRUPT ENABLE */ -+ /* NO INTERRUPT ENABLE */ -+ -+ /* Single UPPER/LOWER TEMPERATURE THRESHOLD for all sensors */ -+ [LOW_THRESH_0] = REG_FIELD(THRESHOLD_ADDR, 0, 7), -+ [UP_THRESH_0] = REG_FIELD(THRESHOLD_ADDR, 8, 15), -+ /* MIN_THRESH_0 and MAX_THRESH_0 are not present in the regfield -+ * Recycle CRIT_THRESH_0 and 1 to set the required regs to hardcoded temp -+ * MIN_THRESH_0 -> CRIT_THRESH_1 -+ * MAX_THRESH_0 -> CRIT_THRESH_0 -+ */ -+ [CRIT_THRESH_1] = REG_FIELD(THRESHOLD_ADDR, 16, 23), -+ [CRIT_THRESH_0] = REG_FIELD(THRESHOLD_ADDR, 24, 31), -+ -+ /* UPPER/LOWER INTERRUPT [CLEAR/STATUS] */ -+ /* 1 == clear, 0 == normal operation */ -+ [LOW_INT_CLEAR_0] = REG_FIELD(CNTL_ADDR, 9, 9), -+ [UP_INT_CLEAR_0] = REG_FIELD(CNTL_ADDR, 10, 10), -+ -+ /* NO CRITICAL INTERRUPT SUPPORT on 8960 */ -+ -+ /* Sn_STATUS */ -+ [LAST_TEMP_0] = REG_FIELD(S0_STATUS_OFF, 0, 7), -+ [LAST_TEMP_1] = REG_FIELD(S1_STATUS_OFF, 0, 7), -+ [LAST_TEMP_2] = REG_FIELD(S2_STATUS_OFF, 0, 7), -+ [LAST_TEMP_3] = REG_FIELD(S3_STATUS_OFF, 0, 7), -+ [LAST_TEMP_4] = REG_FIELD(S4_STATUS_OFF, 0, 7), -+ [LAST_TEMP_5] = REG_FIELD(S5_STATUS_OFF, 0, 7), -+ [LAST_TEMP_6] = REG_FIELD(S6_STATUS_OFF, 0, 7), -+ [LAST_TEMP_7] = REG_FIELD(S7_STATUS_OFF, 0, 7), -+ [LAST_TEMP_8] = REG_FIELD(S8_STATUS_OFF, 0, 7), -+ [LAST_TEMP_9] = REG_FIELD(S9_STATUS_OFF, 0, 7), -+ [LAST_TEMP_10] = REG_FIELD(S10_STATUS_OFF, 0, 7), -+ -+ /* No VALID field on 8960 */ -+ /* TSENS_INT_STATUS bits: 1 == threshold violated */ -+ [MIN_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 0, 0), -+ [LOWER_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 1, 1), -+ [UPPER_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 2, 2), -+ /* No CRITICAL field on 8960 */ -+ [MAX_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 3, 3), -+ -+ /* TRDY: 1=ready, 0=in progress */ -+ [TRDY] = REG_FIELD(INT_STATUS_ADDR, 7, 7), -+}; -+ - static const struct tsens_ops ops_8960 = { - .init = init_8960, - .calibrate = calibrate_8960, -@@ -282,4 +358,6 @@ static const struct tsens_ops ops_8960 = - struct tsens_plat_data data_8960 = { - .num_sensors = 11, - .ops = &ops_8960, -+ .feat = &tsens_8960_feat, -+ .fields = tsens_8960_regfields, - }; diff --git a/target/linux/ipq806x/patches-5.15/104-4-drivers-thermal-tsens-Use-init_common-for-msm8960.patch b/target/linux/ipq806x/patches-5.15/104-4-drivers-thermal-tsens-Use-init_common-for-msm8960.patch deleted file mode 100644 index ae8a52c100..0000000000 --- a/target/linux/ipq806x/patches-5.15/104-4-drivers-thermal-tsens-Use-init_common-for-msm8960.patch +++ /dev/null @@ -1,81 +0,0 @@ -From c04f98a496929f75d75c65115d5717423c3d0634 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith <ansuelsmth@gmail.com> -Date: Wed, 25 Nov 2020 17:16:36 +0100 -Subject: [PATCH 04/10] drivers: thermal: tsens: Use init_common for msm8960 - -Use init_common and drop custom init for msm8960. - -Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com> -Reviewed-by: Thara Gopinath <thara.gopinath@linaro.org> ---- - drivers/thermal/qcom/tsens-8960.c | 52 +------------------------------ - 1 file changed, 1 insertion(+), 51 deletions(-) - ---- a/drivers/thermal/qcom/tsens-8960.c -+++ b/drivers/thermal/qcom/tsens-8960.c -@@ -173,56 +173,6 @@ static void disable_8960(struct tsens_pr - regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl); - } - --static int init_8960(struct tsens_priv *priv) --{ -- int ret, i; -- u32 reg_cntl; -- -- priv->tm_map = dev_get_regmap(priv->dev, NULL); -- if (!priv->tm_map) -- return -ENODEV; -- -- /* -- * The status registers for each sensor are discontiguous -- * because some SoCs have 5 sensors while others have more -- * but the control registers stay in the same place, i.e -- * directly after the first 5 status registers. -- */ -- for (i = 0; i < priv->num_sensors; i++) { -- if (i >= 5) -- priv->sensor[i].status = S0_STATUS_ADDR + 40; -- priv->sensor[i].status += i * 4; -- } -- -- reg_cntl = SW_RST; -- ret = regmap_update_bits(priv->tm_map, CNTL_ADDR, SW_RST, reg_cntl); -- if (ret) -- return ret; -- -- if (priv->num_sensors > 1) { -- reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18); -- reg_cntl &= ~SW_RST; -- ret = regmap_update_bits(priv->tm_map, CONFIG_ADDR, -- CONFIG_MASK, CONFIG); -- } else { -- reg_cntl |= SLP_CLK_ENA_8660 | (MEASURE_PERIOD << 16); -- reg_cntl &= ~CONFIG_MASK_8660; -- reg_cntl |= CONFIG_8660 << CONFIG_SHIFT_8660; -- } -- -- reg_cntl |= GENMASK(priv->num_sensors - 1, 0) << SENSOR0_SHIFT; -- ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl); -- if (ret) -- return ret; -- -- reg_cntl |= EN; -- ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl); -- if (ret) -- return ret; -- -- return 0; --} -- - static int calibrate_8960(struct tsens_priv *priv) - { - int i; -@@ -346,7 +296,7 @@ static const struct reg_field tsens_8960 - }; - - static const struct tsens_ops ops_8960 = { -- .init = init_8960, -+ .init = init_common, - .calibrate = calibrate_8960, - .get_temp = get_temp_8960, - .enable = enable_8960, diff --git a/target/linux/ipq806x/patches-5.15/104-5-drivers-thermal-tsens-Fix-bug-in-sensor-enable-for-m.patch b/target/linux/ipq806x/patches-5.15/104-5-drivers-thermal-tsens-Fix-bug-in-sensor-enable-for-m.patch deleted file mode 100644 index 7b01a67d90..0000000000 --- a/target/linux/ipq806x/patches-5.15/104-5-drivers-thermal-tsens-Fix-bug-in-sensor-enable-for-m.patch +++ /dev/null @@ -1,66 +0,0 @@ -From b3e8bd33b84a6b6c863bd1733bd15b5f1483b8ab Mon Sep 17 00:00:00 2001 -From: Ansuel Smith <ansuelsmth@gmail.com> -Date: Wed, 25 Nov 2020 17:06:55 +0100 -Subject: [PATCH 05/10] drivers: thermal: tsens: Fix bug in sensor enable for - msm8960 - -Device based on tsens VER_0 contains a hardware bug that results in some -problem with sensor enablement. Sensor id 6-11 can't be enabled -selectively and all of them must be enabled in one step. - -Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com> -Acked-by: Thara Gopinath <thara.gopinath@linaro.org> ---- - drivers/thermal/qcom/tsens-8960.c | 23 ++++++++++++++++++++--- - 1 file changed, 20 insertions(+), 3 deletions(-) - ---- a/drivers/thermal/qcom/tsens-8960.c -+++ b/drivers/thermal/qcom/tsens-8960.c -@@ -27,9 +27,9 @@ - #define EN BIT(0) - #define SW_RST BIT(1) - #define SENSOR0_EN BIT(3) -+#define MEASURE_PERIOD BIT(18) - #define SLP_CLK_ENA BIT(26) - #define SLP_CLK_ENA_8660 BIT(24) --#define MEASURE_PERIOD 1 - #define SENSOR0_SHIFT 3 - - /* INT_STATUS_ADDR bitmasks */ -@@ -126,17 +126,34 @@ static int resume_8960(struct tsens_priv - static int enable_8960(struct tsens_priv *priv, int id) - { - int ret; -- u32 reg, mask; -+ u32 reg, mask = BIT(id); - - ret = regmap_read(priv->tm_map, CNTL_ADDR, ®); - if (ret) - return ret; - -- mask = BIT(id + SENSOR0_SHIFT); -+ /* HARDWARE BUG: -+ * On platforms with more than 6 sensors, all remaining sensors -+ * must be enabled together, otherwise undefined results are expected. -+ * (Sensor 6-7 disabled, Sensor 3 disabled...) In the original driver, -+ * all the sensors are enabled in one step hence this bug is not -+ * triggered. -+ */ -+ if (id > 5) -+ mask = GENMASK(10, 6); -+ -+ mask <<= SENSOR0_SHIFT; -+ -+ /* Sensors already enabled. Skip. */ -+ if ((reg & mask) == mask) -+ return 0; -+ - ret = regmap_write(priv->tm_map, CNTL_ADDR, reg | SW_RST); - if (ret) - return ret; - -+ reg |= MEASURE_PERIOD; -+ - if (priv->num_sensors > 1) - reg |= mask | SLP_CLK_ENA | EN; - else diff --git a/target/linux/ipq806x/patches-5.15/104-6-drivers-thermal-tsens-Replace-custom-8960-apis-with-.patch b/target/linux/ipq806x/patches-5.15/104-6-drivers-thermal-tsens-Replace-custom-8960-apis-with-.patch deleted file mode 100644 index a82f596954..0000000000 --- a/target/linux/ipq806x/patches-5.15/104-6-drivers-thermal-tsens-Replace-custom-8960-apis-with-.patch +++ /dev/null @@ -1,109 +0,0 @@ -From 1ff9f982051759e0387e8c7e793b49c48eae291d Mon Sep 17 00:00:00 2001 -From: Ansuel Smith <ansuelsmth@gmail.com> -Date: Wed, 25 Nov 2020 17:11:05 +0100 -Subject: [PATCH 06/10] drivers: thermal: tsens: Replace custom 8960 apis with - generic apis - -Rework calibrate function to use common function. Derive the offset from -a missing hardcoded slope table and the data from the nvmem calib -efuses. -Drop custom get_temp function and use generic api. - -Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com> -Acked-by: Thara Gopinath <thara.gopinath@linaro.org> ---- - drivers/thermal/qcom/tsens-8960.c | 56 +++++++++---------------------- - 1 file changed, 15 insertions(+), 41 deletions(-) - ---- a/drivers/thermal/qcom/tsens-8960.c -+++ b/drivers/thermal/qcom/tsens-8960.c -@@ -67,6 +67,13 @@ - #define S9_STATUS_OFF 0x3674 - #define S10_STATUS_OFF 0x3678 - -+/* Original slope - 200 to compensate mC to C inaccuracy */ -+static u32 tsens_msm8960_slope[] = { -+ 976, 976, 954, 976, -+ 911, 932, 932, 999, -+ 932, 999, 932 -+ }; -+ - static int suspend_8960(struct tsens_priv *priv) - { - int ret; -@@ -194,9 +201,7 @@ static int calibrate_8960(struct tsens_p - { - int i; - char *data; -- -- ssize_t num_read = priv->num_sensors; -- struct tsens_sensor *s = priv->sensor; -+ u32 p1[11]; - - data = qfprom_read(priv->dev, "calib"); - if (IS_ERR(data)) -@@ -204,49 +209,18 @@ static int calibrate_8960(struct tsens_p - if (IS_ERR(data)) - return PTR_ERR(data); - -- for (i = 0; i < num_read; i++, s++) -- s->offset = data[i]; -+ for (i = 0; i < priv->num_sensors; i++) { -+ p1[i] = data[i]; -+ priv->sensor[i].slope = tsens_msm8960_slope[i]; -+ } -+ -+ compute_intercept_slope(priv, p1, NULL, ONE_PT_CALIB); - - kfree(data); - - return 0; - } - --/* Temperature on y axis and ADC-code on x-axis */ --static inline int code_to_mdegC(u32 adc_code, const struct tsens_sensor *s) --{ -- int slope, offset; -- -- slope = thermal_zone_get_slope(s->tzd); -- offset = CAL_MDEGC - slope * s->offset; -- -- return adc_code * slope + offset; --} -- --static int get_temp_8960(const struct tsens_sensor *s, int *temp) --{ -- int ret; -- u32 code, trdy; -- struct tsens_priv *priv = s->priv; -- unsigned long timeout; -- -- timeout = jiffies + usecs_to_jiffies(TIMEOUT_US); -- do { -- ret = regmap_read(priv->tm_map, INT_STATUS_ADDR, &trdy); -- if (ret) -- return ret; -- if (!(trdy & TRDY_MASK)) -- continue; -- ret = regmap_read(priv->tm_map, s->status, &code); -- if (ret) -- return ret; -- *temp = code_to_mdegC(code, s); -- return 0; -- } while (time_before(jiffies, timeout)); -- -- return -ETIMEDOUT; --} -- - static struct tsens_features tsens_8960_feat = { - .ver_major = VER_0, - .crit_int = 0, -@@ -315,7 +289,7 @@ static const struct reg_field tsens_8960 - static const struct tsens_ops ops_8960 = { - .init = init_common, - .calibrate = calibrate_8960, -- .get_temp = get_temp_8960, -+ .get_temp = get_temp_common, - .enable = enable_8960, - .disable = disable_8960, - .suspend = suspend_8960, diff --git a/target/linux/ipq806x/patches-5.15/104-7-drivers-thermal-tsens-Drop-unused-define-for-msm8960.patch b/target/linux/ipq806x/patches-5.15/104-7-drivers-thermal-tsens-Drop-unused-define-for-msm8960.patch deleted file mode 100644 index 77ca3cfe45..0000000000 --- a/target/linux/ipq806x/patches-5.15/104-7-drivers-thermal-tsens-Drop-unused-define-for-msm8960.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 5716a61239c6ac9ceb137e825e93c3aea06c4634 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith <ansuelsmth@gmail.com> -Date: Fri, 19 Mar 2021 00:48:23 +0100 -Subject: [PATCH 07/10] drivers: thermal: tsens: Drop unused define for msm8960 - -Drop unused define for msm8960 replaced by generic api and reg_field. - -Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com> -Reviewed-by: Thara Gopinath <thara.gopinath@linaro.org> ---- - drivers/thermal/qcom/tsens-8960.c | 24 +----------------------- - 1 file changed, 1 insertion(+), 23 deletions(-) - ---- a/drivers/thermal/qcom/tsens-8960.c -+++ b/drivers/thermal/qcom/tsens-8960.c -@@ -10,8 +10,6 @@ - #include <linux/thermal.h> - #include "tsens.h" - --#define CAL_MDEGC 30000 -- - #define CONFIG_ADDR 0x3640 - #define CONFIG_ADDR_8660 0x3620 - /* CONFIG_ADDR bitmasks */ -@@ -21,39 +19,19 @@ - #define CONFIG_SHIFT_8660 28 - #define CONFIG_MASK_8660 (3 << CONFIG_SHIFT_8660) - --#define STATUS_CNTL_ADDR_8064 0x3660 - #define CNTL_ADDR 0x3620 - /* CNTL_ADDR bitmasks */ - #define EN BIT(0) - #define SW_RST BIT(1) --#define SENSOR0_EN BIT(3) -+ - #define MEASURE_PERIOD BIT(18) - #define SLP_CLK_ENA BIT(26) - #define SLP_CLK_ENA_8660 BIT(24) - #define SENSOR0_SHIFT 3 - --/* INT_STATUS_ADDR bitmasks */ --#define MIN_STATUS_MASK BIT(0) --#define LOWER_STATUS_CLR BIT(1) --#define UPPER_STATUS_CLR BIT(2) --#define MAX_STATUS_MASK BIT(3) -- - #define THRESHOLD_ADDR 0x3624 --/* THRESHOLD_ADDR bitmasks */ --#define THRESHOLD_MAX_LIMIT_SHIFT 24 --#define THRESHOLD_MIN_LIMIT_SHIFT 16 --#define THRESHOLD_UPPER_LIMIT_SHIFT 8 --#define THRESHOLD_LOWER_LIMIT_SHIFT 0 -- --/* Initial temperature threshold values */ --#define LOWER_LIMIT_TH 0x50 --#define UPPER_LIMIT_TH 0xdf --#define MIN_LIMIT_TH 0x0 --#define MAX_LIMIT_TH 0xff - - #define INT_STATUS_ADDR 0x363c --#define TRDY_MASK BIT(7) --#define TIMEOUT_US 100 - - #define S0_STATUS_OFF 0x3628 - #define S1_STATUS_OFF 0x362c diff --git a/target/linux/ipq806x/patches-5.15/104-8-drivers-thermal-tsens-Add-support-for-ipq8064-tsens.patch b/target/linux/ipq806x/patches-5.15/104-8-drivers-thermal-tsens-Add-support-for-ipq8064-tsens.patch deleted file mode 100644 index 127abaefc3..0000000000 --- a/target/linux/ipq806x/patches-5.15/104-8-drivers-thermal-tsens-Add-support-for-ipq8064-tsens.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 0d0c22a59bf2672b57e23da9a9ea743e91b71f54 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith <ansuelsmth@gmail.com> -Date: Sat, 25 Jul 2020 19:55:57 +0200 -Subject: [PATCH 08/10] drivers: thermal: tsens: Add support for ipq8064-tsens - -Add support for tsens present in ipq806x SoCs based on generic msm8960 -tsens driver. - -Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com> -Reviewed-by: Thara Gopinath <thara.gopinath@linaro.org> ---- - drivers/thermal/qcom/tsens.c | 3 +++ - 1 file changed, 3 insertions(+) - ---- a/drivers/thermal/qcom/tsens.c -+++ b/drivers/thermal/qcom/tsens.c -@@ -968,6 +968,9 @@ static SIMPLE_DEV_PM_OPS(tsens_pm_ops, t - - static const struct of_device_id tsens_table[] = { - { -+ .compatible = "qcom,ipq8064-tsens", -+ .data = &data_8960, -+ }, { - .compatible = "qcom,msm8916-tsens", - .data = &data_8916, - }, { diff --git a/target/linux/ipq806x/patches-5.15/104-9-dt-bindings-thermal-tsens-Document-ipq8064-bindings.patch b/target/linux/ipq806x/patches-5.15/104-9-dt-bindings-thermal-tsens-Document-ipq8064-bindings.patch deleted file mode 100644 index 382106863f..0000000000 --- a/target/linux/ipq806x/patches-5.15/104-9-dt-bindings-thermal-tsens-Document-ipq8064-bindings.patch +++ /dev/null @@ -1,112 +0,0 @@ -From ac369071920d427dd484cf74cddba2774bba45f5 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith <ansuelsmth@gmail.com> -Date: Thu, 9 Jul 2020 22:35:54 +0200 -Subject: [PATCH 09/10] dt-bindings: thermal: tsens: Document ipq8064 bindings - -Document the use of bindings used for msm8960 tsens based devices. -msm8960 use the same gcc regs and is set as a child of the qcom gcc. - -Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com> -Reviewed-by: Rob Herring <robh@kernel.org> ---- - .../bindings/thermal/qcom-tsens.yaml | 56 ++++++++++++++++--- - 1 file changed, 48 insertions(+), 8 deletions(-) - ---- a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml -+++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml -@@ -19,6 +19,11 @@ description: | - properties: - compatible: - oneOf: -+ - description: msm9860 TSENS based -+ items: -+ - enum: -+ - qcom,ipq8064-tsens -+ - - description: v0.1 of TSENS - items: - - enum: -@@ -73,7 +78,9 @@ properties: - maxItems: 2 - items: - - const: calib -- - const: calib_sel -+ - enum: -+ - calib_backup -+ - calib_sel - - "#qcom,sensors": - description: -@@ -88,12 +95,20 @@ properties: - Number of cells required to uniquely identify the thermal sensors. Since - we have multiple sensors this is set to 1 - -+required: -+ - compatible -+ - interrupts -+ - interrupt-names -+ - "#thermal-sensor-cells" -+ - "#qcom,sensors" -+ - allOf: - - if: - properties: - compatible: - contains: - enum: -+ - qcom,ipq8064-tsens - - qcom,msm8916-tsens - - qcom,msm8974-tsens - - qcom,msm8976-tsens -@@ -114,19 +129,44 @@ allOf: - interrupt-names: - minItems: 2 - --required: -- - compatible -- - reg -- - "#qcom,sensors" -- - interrupts -- - interrupt-names -- - "#thermal-sensor-cells" -+ - if: -+ properties: -+ compatible: -+ contains: -+ enum: -+ - qcom,tsens-v0_1 -+ - qcom,tsens-v1 -+ - qcom,tsens-v2 -+ -+ then: -+ required: -+ - reg - - additionalProperties: false - - examples: - - | - #include <dt-bindings/interrupt-controller/arm-gic.h> -+ // Example msm9860 based SoC (ipq8064): -+ gcc: clock-controller { -+ -+ /* ... */ -+ -+ tsens: thermal-sensor { -+ compatible = "qcom,ipq8064-tsens"; -+ -+ nvmem-cells = <&tsens_calib>, <&tsens_calib_backup>; -+ nvmem-cell-names = "calib", "calib_backup"; -+ interrupts = <GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH>; -+ interrupt-names = "uplow"; -+ -+ #qcom,sensors = <11>; -+ #thermal-sensor-cells = <1>; -+ }; -+ }; -+ -+ - | -+ #include <dt-bindings/interrupt-controller/arm-gic.h> - // Example 1 (legacy: for pre v1 IP): - tsens1: thermal-sensor@900000 { - compatible = "qcom,msm8916-tsens", "qcom,tsens-v0_1"; diff --git a/target/linux/ipq806x/patches-5.15/105-10-drivers-thermal-tsens-Fix-wrong-slope-on-msm-8960.patch b/target/linux/ipq806x/patches-5.15/105-10-drivers-thermal-tsens-Fix-wrong-slope-on-msm-8960.patch deleted file mode 100644 index 6cdc0b263f..0000000000 --- a/target/linux/ipq806x/patches-5.15/105-10-drivers-thermal-tsens-Fix-wrong-slope-on-msm-8960.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 68e720ed73c8f038c8c500e4c49c1e65a993a448 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith <ansuelsmth@gmail.com> -Date: Tue, 6 Apr 2021 04:45:31 +0200 -Subject: [PATCH 10/10] drivers: thermal: tsens: Fix wrong slope on msm-8960 - -Some user using some stats with the old legacy implementation and the -new implementation using the compute_intercept_slope reported an offset -of 3C. Fix the slope table to reflect the original temp. - -Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com> ---- - drivers/thermal/qcom/tsens-8960.c | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - ---- a/drivers/thermal/qcom/tsens-8960.c -+++ b/drivers/thermal/qcom/tsens-8960.c -@@ -45,11 +45,11 @@ - #define S9_STATUS_OFF 0x3674 - #define S10_STATUS_OFF 0x3678 - --/* Original slope - 200 to compensate mC to C inaccuracy */ -+/* Original slope - 350 to compensate mC to C inaccuracy */ - static u32 tsens_msm8960_slope[] = { -- 976, 976, 954, 976, -- 911, 932, 932, 999, -- 932, 999, 932 -+ 826, 826, 804, 826, -+ 761, 782, 782, 849, -+ 782, 849, 782 - }; - - static int suspend_8960(struct tsens_priv *priv) diff --git a/target/linux/ipq806x/patches-5.15/108-v5.14-net-stmmac-explicitly-deassert-gmac-ahb-reset.patch b/target/linux/ipq806x/patches-5.15/108-v5.14-net-stmmac-explicitly-deassert-gmac-ahb-reset.patch deleted file mode 100644 index dd1e506e5b..0000000000 --- a/target/linux/ipq806x/patches-5.15/108-v5.14-net-stmmac-explicitly-deassert-gmac-ahb-reset.patch +++ /dev/null @@ -1,75 +0,0 @@ -From e67f325e9cd67562b761e884680c0fec03a6f404 Mon Sep 17 00:00:00 2001 -From: Matthew Hagan <mnhagan88@gmail.com> -Date: Tue, 8 Jun 2021 19:59:06 +0100 -Subject: net: stmmac: explicitly deassert GMAC_AHB_RESET - -We are currently assuming that GMAC_AHB_RESET will already be deasserted -by the bootloader. However if this has not been done, probing of the GMAC -will fail. To remedy this we must ensure GMAC_AHB_RESET has been deasserted -prior to probing. - -v2 changes: - - remove NULL condition check for stmmac_ahb_rst in stmmac_main.c - - unwrap dev_err() message in stmmac_main.c - - add PTR_ERR() around plat->stmmac_ahb_rst in stmmac_platform.c - -v3 changes: - - add error pointer to dev_err() output - - add reset_control_assert(stmmac_ahb_rst) in stmmac_dvr_remove - - revert PTR_ERR() around plat->stmmac_ahb_rst since this is performed - on the returned value of ret by the calling function - -Signed-off-by: Matthew Hagan <mnhagan88@gmail.com> -Signed-off-by: David S. Miller <davem@davemloft.net> ---- - drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 5 +++++ - drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 6 ++++++ - include/linux/stmmac.h | 1 + - 3 files changed, 12 insertions(+) - ---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c -+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c -@@ -5021,6 +5021,10 @@ int stmmac_dvr_probe(struct device *devi - reset_control_reset(priv->plat->stmmac_rst); - } - -+ ret = reset_control_deassert(priv->plat->stmmac_ahb_rst); -+ if (ret == -ENOTSUPP) -+ dev_err(priv->device, "unable to bring out of ahb reset\n"); -+ - /* Init MAC and get the capabilities */ - ret = stmmac_hw_init(priv); - if (ret) -@@ -5245,6 +5249,7 @@ int stmmac_dvr_remove(struct device *dev - phylink_destroy(priv->phylink); - if (priv->plat->stmmac_rst) - reset_control_assert(priv->plat->stmmac_rst); -+ reset_control_assert(priv->plat->stmmac_ahb_rst); - pm_runtime_put(dev); - pm_runtime_disable(dev); - if (priv->hw->pcs != STMMAC_PCS_TBI && ---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c -+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c -@@ -617,6 +617,12 @@ stmmac_probe_config_dt(struct platform_d - plat->stmmac_rst = NULL; - } - -+ plat->stmmac_ahb_rst = devm_reset_control_get_optional_shared( -+ &pdev->dev, "ahb"); -+ if (IS_ERR(plat->stmmac_ahb_rst)) -+ if (PTR_ERR(plat->stmmac_ahb_rst) == -EPROBE_DEFER) -+ goto error_hw_init; -+ - return plat; - - error_hw_init: ---- a/include/linux/stmmac.h -+++ b/include/linux/stmmac.h -@@ -192,6 +192,7 @@ struct plat_stmmacenet_data { - unsigned int clk_ref_rate; - s32 ptp_max_adj; - struct reset_control *stmmac_rst; -+ struct reset_control *stmmac_ahb_rst; - struct stmmac_axi *axi; - int has_gmac4; - bool has_sun8i; diff --git a/target/linux/ipq806x/patches-5.15/109-v5.15-arm-dts-qcom-add-ahb-reset-to-ipq806x-gmac.patch b/target/linux/ipq806x/patches-5.15/109-v5.15-arm-dts-qcom-add-ahb-reset-to-ipq806x-gmac.patch deleted file mode 100644 index 4a047ed6eb..0000000000 --- a/target/linux/ipq806x/patches-5.15/109-v5.15-arm-dts-qcom-add-ahb-reset-to-ipq806x-gmac.patch +++ /dev/null @@ -1,64 +0,0 @@ -From f95c4c56d65225a537a2d88735fde7ec4d37641d Mon Sep 17 00:00:00 2001 -From: Matthew Hagan <mnhagan88@gmail.com> -Date: Sat, 5 Jun 2021 18:35:38 +0100 -Subject: ARM: dts: qcom: add ahb reset to ipq806x-gmac - -Add GMAC_AHB_RESET to the resets property of each gmac node. - -Signed-off-by: Matthew Hagan <mnhagan88@gmail.com> -Link: https://lore.kernel.org/r/20210605173546.4102455-2-mnhagan88@gmail.com -Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org> ---- - arch/arm/boot/dts/qcom-ipq8064.dtsi | 20 ++++++++++++-------- - 1 file changed, 12 insertions(+), 8 deletions(-) - ---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi -+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi -@@ -1335,8 +1335,9 @@ - clocks = <&gcc GMAC_CORE1_CLK>; - clock-names = "stmmaceth"; - -- resets = <&gcc GMAC_CORE1_RESET>; -- reset-names = "stmmaceth"; -+ resets = <&gcc GMAC_CORE1_RESET>, -+ <&gcc GMAC_AHB_RESET>; -+ reset-names = "stmmaceth", "ahb"; - - status = "disabled"; - }; -@@ -1358,8 +1359,9 @@ - clocks = <&gcc GMAC_CORE2_CLK>; - clock-names = "stmmaceth"; - -- resets = <&gcc GMAC_CORE2_RESET>; -- reset-names = "stmmaceth"; -+ resets = <&gcc GMAC_CORE2_RESET>, -+ <&gcc GMAC_AHB_RESET>; -+ reset-names = "stmmaceth", "ahb"; - - status = "disabled"; - }; -@@ -1381,8 +1383,9 @@ - clocks = <&gcc GMAC_CORE3_CLK>; - clock-names = "stmmaceth"; - -- resets = <&gcc GMAC_CORE3_RESET>; -- reset-names = "stmmaceth"; -+ resets = <&gcc GMAC_CORE3_RESET>, -+ <&gcc GMAC_AHB_RESET>; -+ reset-names = "stmmaceth", "ahb"; - - status = "disabled"; - }; -@@ -1404,8 +1407,9 @@ - clocks = <&gcc GMAC_CORE4_CLK>; - clock-names = "stmmaceth"; - -- resets = <&gcc GMAC_CORE4_RESET>; -- reset-names = "stmmaceth"; -+ resets = <&gcc GMAC_CORE4_RESET>, -+ <&gcc GMAC_AHB_RESET>; -+ reset-names = "stmmaceth", "ahb"; - - status = "disabled"; - }; |