mirror of
https://github.com/torvalds/linux.git
synced 2026-08-02 05:12:01 +02:00
Merge "dma: qcom: bam_dma: Add QCOM BAM DMA driver snapshot"
This commit is contained in:
commit
bc131a4f9d
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2013-2014, 2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
/*
|
||||
* QCOM BAM DMA engine driver
|
||||
|
|
@ -41,6 +42,7 @@
|
|||
#include <linux/clk.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/ipc_logging.h>
|
||||
|
||||
#include "../dmaengine.h"
|
||||
#include "../virt-dma.h"
|
||||
|
|
@ -59,6 +61,41 @@ struct bam_desc_hw {
|
|||
#define DESC_FLAG_NWD BIT(12)
|
||||
#define DESC_FLAG_CMD BIT(11)
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include "bam_dma_trace.h"
|
||||
|
||||
/* FTRACE Logging */
|
||||
static void __ftrace_dbg(struct device *dev, const char *fmt, ...)
|
||||
{
|
||||
struct va_format vaf = {
|
||||
.fmt = fmt,
|
||||
};
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
vaf.va = &args;
|
||||
trace_bam_dma_info(dev_name(dev), &vaf);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
#define ftrace_dbg(dev, fmt, ...) \
|
||||
__ftrace_dbg(dev, fmt, ##__VA_ARGS__)\
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
#define DMA_IPC_LOGPAGES 1
|
||||
#define DMA_BAM_DBG(ctxt, dev, fmt...) do { \
|
||||
if (ctxt) { \
|
||||
ipc_log_string(ctxt, fmt); \
|
||||
} \
|
||||
ftrace_dbg(dev, fmt); \
|
||||
} while (0)
|
||||
#else
|
||||
#define DMA_BAM_DBG(ctxt, dev, fmt...) do { \
|
||||
pr_debug(fmt); \
|
||||
ftrace_dbg(dev, fmt); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
struct bam_async_desc {
|
||||
struct virt_dma_desc vd;
|
||||
|
||||
|
|
@ -338,7 +375,10 @@ static const struct reg_offset_data bam_v1_7_reg_info[] = {
|
|||
/* BAM_P_SW_OFSTS */
|
||||
#define P_SW_OFSTS_MASK 0xffff
|
||||
|
||||
#define BAM_DESC_FIFO_SIZE SZ_32K
|
||||
#define MSM_SLIM_DESC_NUM 32
|
||||
#define MSM_SLIM_DESC_FIFO_SIZE (MSM_SLIM_DESC_NUM * 8)
|
||||
#define BAM_DESC_FIFO_SIZE (bdev->r_mem.is_r_mem ? (MSM_SLIM_DESC_FIFO_SIZE) : SZ_32K)
|
||||
|
||||
#define MAX_DESCRIPTORS (BAM_DESC_FIFO_SIZE / sizeof(struct bam_desc_hw) - 1)
|
||||
#define BAM_FIFO_SIZE (SZ_32K - 8)
|
||||
#define IS_BUSY(chan) (CIRC_SPACE(bchan->tail, bchan->head,\
|
||||
|
|
@ -377,6 +417,26 @@ static inline struct bam_chan *to_bam_chan(struct dma_chan *common)
|
|||
return container_of(common, struct bam_chan, vc.chan);
|
||||
}
|
||||
|
||||
/**
|
||||
* struct remote_mem - Stores remote memory information
|
||||
* @r_res: Memory resource structure parsed from devicetree
|
||||
* @r_vbase: Virtual base address of remote memory region
|
||||
* @r_vsbase: Saved virtual base address of remote memory region
|
||||
* @r_pbase: Physical base address of remote memory region
|
||||
* @is_r_mem: Indicates if remote memory is used or not
|
||||
*
|
||||
* Some BAM clients require the use of a specific memory region for the
|
||||
* pipe descriptor fifo. This structure is used to hold the remote
|
||||
* memory region information.
|
||||
*/
|
||||
struct remote_mem {
|
||||
struct resource *r_res;
|
||||
void __iomem *r_vbase;
|
||||
void __iomem *r_vsbase;
|
||||
u32 r_pbase;
|
||||
bool is_r_mem;
|
||||
};
|
||||
|
||||
struct bam_device {
|
||||
void __iomem *regs;
|
||||
struct device *dev;
|
||||
|
|
@ -398,6 +458,9 @@ struct bam_device {
|
|||
|
||||
/* dma start transaction tasklet */
|
||||
struct tasklet_struct task;
|
||||
struct remote_mem r_mem;
|
||||
|
||||
void *ipc_log_dma;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -500,7 +563,7 @@ static void bam_chan_init_hw(struct bam_chan *bchan,
|
|||
*/
|
||||
writel_relaxed(ALIGN(bchan->fifo_phys, sizeof(struct bam_desc_hw)),
|
||||
bam_addr(bdev, bchan->id, BAM_P_DESC_FIFO_ADDR));
|
||||
writel_relaxed(BAM_FIFO_SIZE,
|
||||
writel_relaxed(BAM_DESC_FIFO_SIZE,
|
||||
bam_addr(bdev, bchan->id, BAM_P_FIFO_SIZES));
|
||||
|
||||
/* enable the per pipe interrupts, enable EOT, ERR, and INT irqs */
|
||||
|
|
@ -527,6 +590,9 @@ static void bam_chan_init_hw(struct bam_chan *bchan,
|
|||
/* init FIFO pointers */
|
||||
bchan->head = 0;
|
||||
bchan->tail = 0;
|
||||
|
||||
DMA_BAM_DBG(bdev->ipc_log_dma, bdev->dev,
|
||||
"%s: bam_desc_fifo:%d\n", __func__, BAM_DESC_FIFO_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -543,9 +609,25 @@ static int bam_alloc_chan(struct dma_chan *chan)
|
|||
if (bchan->fifo_virt)
|
||||
return 0;
|
||||
|
||||
/* allocate FIFO descriptor space, but only if necessary */
|
||||
bchan->fifo_virt = dma_alloc_wc(bdev->dev, BAM_DESC_FIFO_SIZE,
|
||||
if (bdev->r_mem.is_r_mem) {
|
||||
bchan->fifo_virt = bdev->r_mem.r_vbase;
|
||||
bchan->fifo_phys = bdev->r_mem.r_res->start;
|
||||
} else {
|
||||
/* allocate FIFO descriptor space, but only if necessary */
|
||||
bchan->fifo_virt = dma_alloc_wc(bdev->dev, BAM_DESC_FIFO_SIZE,
|
||||
&bchan->fifo_phys, GFP_KERNEL);
|
||||
}
|
||||
|
||||
if (bdev->r_mem.is_r_mem) {
|
||||
memset_io(bchan->fifo_virt, 0x0, MSM_SLIM_DESC_NUM * 8);
|
||||
bdev->r_mem.r_vbase = bdev->r_mem.r_vbase + (MSM_SLIM_DESC_NUM * 8);
|
||||
bdev->r_mem.r_res->start = bdev->r_mem.r_res->start + (MSM_SLIM_DESC_NUM * 8);
|
||||
|
||||
DMA_BAM_DBG(bdev->ipc_log_dma, bdev->dev,
|
||||
"dma_bam:%s: r_mem_virt_base:%x r_mem_start:%x\n",
|
||||
__func__, bdev->r_mem.r_vbase,
|
||||
bdev->r_mem.r_res->start);
|
||||
}
|
||||
|
||||
if (!bchan->fifo_virt) {
|
||||
dev_err(bdev->dev, "Failed to allocate desc fifo\n");
|
||||
|
|
@ -554,7 +636,8 @@ static int bam_alloc_chan(struct dma_chan *chan)
|
|||
|
||||
if (bdev->active_channels++ == 0 && bdev->powered_remotely)
|
||||
bam_reset(bdev);
|
||||
|
||||
DMA_BAM_DBG(bdev->ipc_log_dma, bdev->dev,
|
||||
"%s chan id:%d\n", __func__, bchan->id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -573,6 +656,8 @@ static void bam_free_chan(struct dma_chan *chan)
|
|||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
DMA_BAM_DBG(bdev->ipc_log_dma, bdev->dev,
|
||||
"%s chan id:%d\n", __func__, bchan->id);
|
||||
ret = pm_runtime_get_sync(bdev->dev);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
|
@ -588,9 +673,16 @@ static void bam_free_chan(struct dma_chan *chan)
|
|||
bam_reset_channel(bchan);
|
||||
spin_unlock_irqrestore(&bchan->vc.lock, flags);
|
||||
|
||||
dma_free_wc(bdev->dev, BAM_DESC_FIFO_SIZE, bchan->fifo_virt,
|
||||
if (!bdev->r_mem.is_r_mem) {
|
||||
dma_free_wc(bdev->dev, BAM_DESC_FIFO_SIZE, bchan->fifo_virt,
|
||||
bchan->fifo_phys);
|
||||
} else {
|
||||
bdev->r_mem.r_vbase = bdev->r_mem.r_vsbase;
|
||||
bdev->r_mem.r_res->start = bdev->r_mem.r_pbase;
|
||||
}
|
||||
|
||||
bchan->fifo_virt = NULL;
|
||||
bchan->fifo_phys = 0;
|
||||
|
||||
/* mask irq for pipe/channel */
|
||||
val = readl_relaxed(bam_addr(bdev, 0, BAM_IRQ_SRCS_MSK_EE));
|
||||
|
|
@ -626,6 +718,8 @@ static int bam_slave_config(struct dma_chan *chan,
|
|||
struct bam_chan *bchan = to_bam_chan(chan);
|
||||
unsigned long flag;
|
||||
|
||||
DMA_BAM_DBG(bchan->bdev->ipc_log_dma, bchan->bdev->dev,
|
||||
"%s chan id:%d\n", __func__, bchan->id);
|
||||
spin_lock_irqsave(&bchan->vc.lock, flag);
|
||||
memcpy(&bchan->slave, cfg, sizeof(*cfg));
|
||||
bchan->reconfigure = 1;
|
||||
|
|
@ -657,7 +751,8 @@ static struct dma_async_tx_descriptor *bam_prep_slave_sg(struct dma_chan *chan,
|
|||
struct bam_desc_hw *desc;
|
||||
unsigned int num_alloc = 0;
|
||||
|
||||
|
||||
DMA_BAM_DBG(bdev->ipc_log_dma, bdev->dev,
|
||||
"%s DMA direction:%d\n", __func__, direction);
|
||||
if (!is_slave_direction(direction)) {
|
||||
dev_err(bdev->dev, "invalid dma direction\n");
|
||||
return NULL;
|
||||
|
|
@ -729,6 +824,8 @@ static int bam_dma_terminate_all(struct dma_chan *chan)
|
|||
unsigned long flag;
|
||||
LIST_HEAD(head);
|
||||
|
||||
DMA_BAM_DBG(bchan->bdev->ipc_log_dma, bchan->bdev->dev,
|
||||
"%s chan id:%d\n", __func__, bchan->id);
|
||||
/* remove all transactions, including active transaction */
|
||||
spin_lock_irqsave(&bchan->vc.lock, flag);
|
||||
/*
|
||||
|
|
@ -776,6 +873,8 @@ static int bam_pause(struct dma_chan *chan)
|
|||
unsigned long flag;
|
||||
int ret;
|
||||
|
||||
DMA_BAM_DBG(bdev->ipc_log_dma, bdev->dev,
|
||||
"%s chan id:%d\n", __func__, bchan->id);
|
||||
ret = pm_runtime_get_sync(bdev->dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
|
@ -802,6 +901,8 @@ static int bam_resume(struct dma_chan *chan)
|
|||
unsigned long flag;
|
||||
int ret;
|
||||
|
||||
DMA_BAM_DBG(bdev->ipc_log_dma, bdev->dev,
|
||||
"%s chan id:%d\n", __func__, bchan->id);
|
||||
ret = pm_runtime_get_sync(bdev->dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
|
@ -952,6 +1053,8 @@ static enum dma_status bam_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
|
|||
unsigned int i;
|
||||
unsigned long flags;
|
||||
|
||||
DMA_BAM_DBG(bchan->bdev->ipc_log_dma, bchan->bdev->dev,
|
||||
"%s chan id:%d\n", __func__, bchan->id);
|
||||
ret = dma_cookie_status(chan, cookie, txstate);
|
||||
if (ret == DMA_COMPLETE)
|
||||
return ret;
|
||||
|
|
@ -1024,6 +1127,8 @@ static void bam_start_dma(struct bam_chan *bchan)
|
|||
unsigned int avail;
|
||||
struct dmaengine_desc_callback cb;
|
||||
|
||||
DMA_BAM_DBG(bdev->ipc_log_dma, bdev->dev,
|
||||
"%s chan id:%d\n", __func__, bchan->id);
|
||||
lockdep_assert_held(&bchan->vc.lock);
|
||||
|
||||
if (!vd)
|
||||
|
|
@ -1140,8 +1245,11 @@ static void dma_tasklet(struct tasklet_struct *t)
|
|||
static void bam_issue_pending(struct dma_chan *chan)
|
||||
{
|
||||
struct bam_chan *bchan = to_bam_chan(chan);
|
||||
struct bam_device *bdev = bchan->bdev;
|
||||
unsigned long flags;
|
||||
|
||||
DMA_BAM_DBG(bdev->ipc_log_dma, bdev->dev,
|
||||
"%s chan id:%d\n", __func__, bchan->id);
|
||||
spin_lock_irqsave(&bchan->vc.lock, flags);
|
||||
|
||||
/* if work pending and idle, start a transaction */
|
||||
|
|
@ -1171,6 +1279,8 @@ static struct dma_chan *bam_dma_xlate(struct of_phandle_args *dma_spec,
|
|||
struct bam_device, common);
|
||||
unsigned int request;
|
||||
|
||||
DMA_BAM_DBG(bdev->ipc_log_dma, bdev->dev,
|
||||
"%s No of channels:%d\n", __func__, bdev->num_channels);
|
||||
if (dma_spec->args_count != 1)
|
||||
return NULL;
|
||||
|
||||
|
|
@ -1210,6 +1320,8 @@ static int bam_init(struct bam_device *bdev)
|
|||
if (!bdev->controlled_remotely && !bdev->powered_remotely)
|
||||
bam_reset(bdev);
|
||||
|
||||
DMA_BAM_DBG(bdev->ipc_log_dma, bdev->dev,
|
||||
"%s ret:%d\n", __func__, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1238,6 +1350,7 @@ static int bam_dma_probe(struct platform_device *pdev)
|
|||
struct bam_device *bdev;
|
||||
const struct of_device_id *match;
|
||||
struct resource *iores;
|
||||
struct resource *remote_res;
|
||||
int ret, i;
|
||||
|
||||
bdev = devm_kzalloc(&pdev->dev, sizeof(*bdev), GFP_KERNEL);
|
||||
|
|
@ -1254,11 +1367,42 @@ static int bam_dma_probe(struct platform_device *pdev)
|
|||
|
||||
bdev->layout = match->data;
|
||||
|
||||
bdev->ipc_log_dma = ipc_log_context_create(DMA_IPC_LOGPAGES,
|
||||
"dma_bam_log", 0);
|
||||
if (!bdev->ipc_log_dma)
|
||||
dev_err(bdev->dev, "Failed to create dma bam log\n");
|
||||
|
||||
DMA_BAM_DBG(bdev->ipc_log_dma, bdev->dev,
|
||||
"%s start %d\n", __func__, true);
|
||||
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
bdev->regs = devm_ioremap_resource(&pdev->dev, iores);
|
||||
if (IS_ERR(bdev->regs))
|
||||
return PTR_ERR(bdev->regs);
|
||||
|
||||
bdev->r_mem.is_r_mem = false;
|
||||
remote_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
"bam_remote_mem");
|
||||
if (remote_res) {
|
||||
bdev->r_mem.is_r_mem = true;
|
||||
bdev->r_mem.r_pbase = (unsigned long long)remote_res->start;
|
||||
bdev->r_mem.r_vbase = devm_ioremap(&pdev->dev,
|
||||
remote_res->start, resource_size(remote_res));
|
||||
|
||||
if (!bdev->r_mem.r_vbase) {
|
||||
dev_err(&pdev->dev, "Remote mem ioremap failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
bdev->r_mem.r_vsbase = bdev->r_mem.r_vbase;
|
||||
bdev->r_mem.r_res = remote_res;
|
||||
}
|
||||
|
||||
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Could not set 32 bit mask\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
bdev->irq = platform_get_irq(pdev, 0);
|
||||
if (bdev->irq < 0)
|
||||
return bdev->irq;
|
||||
|
|
@ -1373,6 +1517,8 @@ static int bam_dma_probe(struct platform_device *pdev)
|
|||
pm_runtime_set_active(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
DMA_BAM_DBG(bdev->ipc_log_dma, bdev->dev,
|
||||
"%s end ret:%d\n", __func__, 0);
|
||||
return 0;
|
||||
|
||||
err_unregister_dma:
|
||||
|
|
@ -1393,6 +1539,10 @@ static int bam_dma_remove(struct platform_device *pdev)
|
|||
struct bam_device *bdev = platform_get_drvdata(pdev);
|
||||
u32 i;
|
||||
|
||||
DMA_BAM_DBG(bdev->ipc_log_dma, bdev->dev, "%s ret:%d\n", __func__, 0);
|
||||
if (bdev->ipc_log_dma)
|
||||
ipc_log_context_destroy(bdev->ipc_log_dma);
|
||||
|
||||
pm_runtime_force_suspend(&pdev->dev);
|
||||
|
||||
of_dma_controller_free(pdev->dev.of_node);
|
||||
|
|
@ -1452,6 +1602,7 @@ static int __maybe_unused bam_dma_suspend(struct device *dev)
|
|||
pm_runtime_force_suspend(dev);
|
||||
clk_unprepare(bdev->bamclk);
|
||||
|
||||
DMA_BAM_DBG(bdev->ipc_log_dma, bdev->dev, "%s ret:%d\n", __func__, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1466,6 +1617,7 @@ static int __maybe_unused bam_dma_resume(struct device *dev)
|
|||
|
||||
pm_runtime_force_resume(dev);
|
||||
|
||||
DMA_BAM_DBG(bdev->ipc_log_dma, bdev->dev, "%s ret:%d\n", __func__, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
38
drivers/dma/qcom/bam_dma_trace.h
Normal file
38
drivers/dma/qcom/bam_dma_trace.h
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM bam_dma
|
||||
|
||||
#if !defined(_TRACE_BAM_DMA_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
|
||||
#define _TRACE_BAM_DMA_TRACE_H
|
||||
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/tracepoint.h>
|
||||
|
||||
#define MAX_MSG_LEN 200
|
||||
|
||||
TRACE_EVENT(bam_dma_info,
|
||||
TP_PROTO(const char *name, struct va_format *vaf),
|
||||
TP_ARGS(name, vaf),
|
||||
TP_STRUCT__entry
|
||||
(__string(name, name)
|
||||
__dynamic_array(char, msg, MAX_MSG_LEN)
|
||||
),
|
||||
TP_fast_assign
|
||||
(__assign_str(name, name);
|
||||
WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg),
|
||||
MAX_MSG_LEN, vaf->fmt, *vaf->va) >= MAX_MSG_LEN);
|
||||
),
|
||||
TP_printk("%s: %s", __get_str(name), __get_str(msg))
|
||||
);
|
||||
|
||||
#endif /* _TRACE_BAM_DMA_TRACE_H */
|
||||
|
||||
/* This part must be outside protection */
|
||||
#undef TRACE_INCLUDE_PATH
|
||||
#define TRACE_INCLUDE_PATH .
|
||||
#define TRACE_INCLUDE_FILE bam_dma_trace
|
||||
#include <trace/define_trace.h>
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2011-2017, The Linux Foundation
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
|
@ -160,14 +161,15 @@ static int slim_add_device(struct slim_controller *ctrl,
|
|||
sbdev->ctrl = ctrl;
|
||||
INIT_LIST_HEAD(&sbdev->stream_list);
|
||||
spin_lock_init(&sbdev->stream_list_lock);
|
||||
mutex_init(&ctrl->stream_lock);
|
||||
sbdev->dev.of_node = of_node_get(node);
|
||||
sbdev->dev.fwnode = of_fwnode_handle(node);
|
||||
|
||||
dev_set_name(&sbdev->dev, "%x:%x:%x:%x",
|
||||
dev_set_name(&sbdev->dev, "%x:%x:%x:%x%s",
|
||||
sbdev->e_addr.manf_id,
|
||||
sbdev->e_addr.prod_code,
|
||||
sbdev->e_addr.dev_index,
|
||||
sbdev->e_addr.instance);
|
||||
sbdev->e_addr.instance, EXTRA_CHAR);
|
||||
|
||||
return device_register(&sbdev->dev);
|
||||
}
|
||||
|
|
@ -426,10 +428,16 @@ EXPORT_SYMBOL_GPL(of_slim_get_device);
|
|||
static int slim_device_alloc_laddr(struct slim_device *sbdev,
|
||||
bool report_present)
|
||||
{
|
||||
struct slim_controller *ctrl = sbdev->ctrl;
|
||||
struct slim_controller *ctrl;
|
||||
u8 laddr;
|
||||
int ret;
|
||||
|
||||
ctrl = sbdev->ctrl;
|
||||
if (!ctrl) {
|
||||
pr_err("%s: slim_controller is NULL\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&ctrl->lock);
|
||||
if (ctrl->get_laddr) {
|
||||
ret = ctrl->get_laddr(ctrl, &sbdev->e_addr, &laddr);
|
||||
|
|
@ -492,6 +500,14 @@ int slim_device_report_present(struct slim_controller *ctrl,
|
|||
int ret;
|
||||
|
||||
ret = pm_runtime_get_sync(ctrl->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(ctrl->dev, "slim %s: PM get_sync failed ret :%d\n",
|
||||
__func__, ret);
|
||||
pm_runtime_put_noidle(ctrl->dev);
|
||||
/* Set device in suspended since resume failed */
|
||||
pm_runtime_set_suspended(ctrl->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ctrl->sched.clk_state != SLIM_CLK_ACTIVE) {
|
||||
dev_err(ctrl->dev, "slim ctrl not active,state:%d, ret:%d\n",
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2011-2017, The Linux Foundation
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include "slimbus.h"
|
||||
#include <linux/io.h>
|
||||
|
||||
/**
|
||||
* slim_msg_response() - Deliver Message response received from a device to the
|
||||
|
|
@ -42,7 +44,7 @@ void slim_msg_response(struct slim_controller *ctrl, u8 *reply, u8 tid, u8 len)
|
|||
}
|
||||
|
||||
slim_free_txn_tid(ctrl, txn);
|
||||
memcpy(msg->rbuf, reply, len);
|
||||
memcpy_fromio(msg->rbuf, reply, len);
|
||||
if (txn->comp)
|
||||
complete(txn->comp);
|
||||
|
||||
|
|
@ -123,14 +125,6 @@ int slim_do_transfer(struct slim_controller *ctrl, struct slim_msg_txn *txn)
|
|||
txn->mc <= SLIM_MSG_MC_RECONFIGURE_NOW))
|
||||
clk_pause_msg = true;
|
||||
|
||||
if (!clk_pause_msg) {
|
||||
ret = pm_runtime_get_sync(ctrl->dev);
|
||||
if (ctrl->sched.clk_state != SLIM_CLK_ACTIVE) {
|
||||
dev_err(ctrl->dev, "ctrl wrong state:%d, ret:%d\n",
|
||||
ctrl->sched.clk_state, ret);
|
||||
goto slim_xfer_err;
|
||||
}
|
||||
}
|
||||
/* Initialize tid to invalid value */
|
||||
txn->tid = 0;
|
||||
need_tid = slim_tid_txn(txn->mt, txn->mc);
|
||||
|
|
@ -146,6 +140,25 @@ int slim_do_transfer(struct slim_controller *ctrl, struct slim_msg_txn *txn)
|
|||
txn->comp = txn->comp;
|
||||
}
|
||||
|
||||
if (!clk_pause_msg) {
|
||||
ret = pm_runtime_get_sync(ctrl->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(ctrl->dev, "runtime resume failed ret:%d\n",
|
||||
ret);
|
||||
slim_free_txn_tid(ctrl, txn);
|
||||
pm_runtime_put_noidle(ctrl->dev);
|
||||
/* Set device in suspended since resume failed */
|
||||
pm_runtime_set_suspended(ctrl->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ctrl->sched.clk_state != SLIM_CLK_ACTIVE) {
|
||||
dev_err(ctrl->dev, "ctrl wrong state:%d, ret:%d\n",
|
||||
ctrl->sched.clk_state, ret);
|
||||
goto slim_xfer_err;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ctrl->xfer_msg(ctrl, txn);
|
||||
|
||||
if (!ret && need_tid && !txn->msg->comp) {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,10 +1,12 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2011-2017, The Linux Foundation
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DRIVERS_SLIMBUS_H
|
||||
#define _DRIVERS_SLIMBUS_H
|
||||
#include <linux/ipc_logging.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/mutex.h>
|
||||
|
|
@ -87,6 +89,37 @@
|
|||
#define SLIM_LA_MANAGER 0xFF
|
||||
|
||||
#define SLIM_MAX_TIDS 256
|
||||
|
||||
void __slimbus_dbg(const char *func, const char *fmt, ...);
|
||||
#define slimbus_dbg(fmt, ...) \
|
||||
__slimbus_dbg(__func__, \
|
||||
fmt, ##__VA_ARGS__) \
|
||||
|
||||
|
||||
/* slimbus supported frequency values */
|
||||
#define SLIM_FREQ_441 44100
|
||||
#define SLIM_FREQ_882 88200
|
||||
|
||||
/* slimbus base frequency values */
|
||||
#define SLIM_BASE_FREQ_11 11025
|
||||
#define SLIM_BASE_FREQ_4 4000
|
||||
|
||||
/**
|
||||
* This is Workaround implementation to avoid redzone overwritten corruption
|
||||
* causing by ngd child device name change in BT driver, changed device name
|
||||
* must be having the same size according to the device name allocated in
|
||||
* slimbus driver.
|
||||
* Adding EXTRA_CHAR to support the name change as expected name change in
|
||||
* BT driver is not possible due to dependent drivers.
|
||||
*/
|
||||
#define BT_WAR
|
||||
|
||||
#ifdef BT_WAR
|
||||
#define EXTRA_CHAR " "
|
||||
#else
|
||||
#define EXTRA_CHAR ""
|
||||
#endif
|
||||
|
||||
/**
|
||||
* struct slim_framer - Represents SLIMbus framer.
|
||||
* Every controller may have multiple framers. There is 1 active framer device
|
||||
|
|
@ -295,6 +328,7 @@ struct slim_port {
|
|||
* Table 47 of SLIMbus 2.0 specs.
|
||||
* @SLIM_PROTO_ISO: Isochronous Protocol, no flow control as data rate match
|
||||
* channel rate flow control embedded in the data.
|
||||
* @SLIM_RESERVED: Reserved protocol bit specific to satellite driver.
|
||||
* @SLIM_PROTO_PUSH: Pushed Protocol, includes flow control, Used to carry
|
||||
* data whose rate is equal to, or lower than the channel rate.
|
||||
* @SLIM_PROTO_PULL: Pulled Protocol, similar usage as pushed protocol
|
||||
|
|
@ -307,6 +341,7 @@ struct slim_port {
|
|||
*/
|
||||
enum slim_transport_protocol {
|
||||
SLIM_PROTO_ISO = 0,
|
||||
SLIM_RESERVED,
|
||||
SLIM_PROTO_PUSH,
|
||||
SLIM_PROTO_PULL,
|
||||
SLIM_PROTO_LOCKED,
|
||||
|
|
@ -316,6 +351,18 @@ enum slim_transport_protocol {
|
|||
SLIM_PROTO_EXT_HALF_DUP,
|
||||
};
|
||||
|
||||
/*
|
||||
* enum slim_ch_control: Channel control.
|
||||
* Activate will schedule channel and/or group of channels in the TDM frame.
|
||||
* Suspend will keep the schedule but data-transfer won't happen.
|
||||
* Remove will remove the channel/group from the TDM frame.
|
||||
*/
|
||||
enum slim_ch_control {
|
||||
SLIM_CH_ACTIVATE,
|
||||
SLIM_CH_SUSPEND,
|
||||
SLIM_CH_REMOVE,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct slim_stream_runtime - SLIMbus stream runtime instance
|
||||
*
|
||||
|
|
@ -420,8 +467,77 @@ struct slim_controller {
|
|||
int (*enable_stream)(struct slim_stream_runtime *rt);
|
||||
int (*disable_stream)(struct slim_stream_runtime *rt);
|
||||
int (*wakeup)(struct slim_controller *ctrl);
|
||||
struct mutex stream_lock;
|
||||
};
|
||||
|
||||
/* IPC logging stuff */
|
||||
#define IPC_SLIMBUS_LOG_PAGES 10
|
||||
|
||||
/* Log levels */
|
||||
enum {
|
||||
FATAL_LEV = 0U,
|
||||
ERR_LEV = 1U,
|
||||
WARN_LEV = 2U,
|
||||
INFO_LEV = 3U,
|
||||
DBG_LEV = 4U,
|
||||
};
|
||||
|
||||
/* Default IPC log level INFO */
|
||||
#define SLIM_DBG(dev, x...) do { \
|
||||
pr_debug(x); \
|
||||
slimbus_dbg(x); \
|
||||
if (dev->ipc_log_mask >= DBG_LEV) { \
|
||||
ipc_log_string(dev->ipc_slimbus_log, x); \
|
||||
} \
|
||||
if (dev->ipc_log_mask == FATAL_LEV) { \
|
||||
ipc_log_string(dev->ipc_slimbus_log_err, x); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define SLIM_INFO(dev, x...) do { \
|
||||
pr_debug(x); \
|
||||
slimbus_dbg(x); \
|
||||
if (dev->ipc_log_mask >= INFO_LEV) {\
|
||||
ipc_log_string(dev->ipc_slimbus_log, x); \
|
||||
} \
|
||||
if (dev->ipc_log_mask == FATAL_LEV) { \
|
||||
ipc_log_string(dev->ipc_slimbus_log_err, x); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* warnings and errors show up on console always */
|
||||
#define SLIM_WARN(dev, x...) do { \
|
||||
slimbus_dbg(x); \
|
||||
if (dev->ipc_log_mask >= WARN_LEV) { \
|
||||
pr_warn(x); \
|
||||
ipc_log_string(dev->ipc_slimbus_log, x); \
|
||||
} \
|
||||
if (dev->ipc_log_mask == FATAL_LEV) { \
|
||||
ipc_log_string(dev->ipc_slimbus_log_err, x); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* ERROR condition in the driver sets the ipc_log_mask
|
||||
* to ERR_FATAL level, so that this message can be seen
|
||||
* in IPC logging. Further errors continue to log on the error IPC logging.
|
||||
*/
|
||||
#define SLIM_ERR(dev, x...) do { \
|
||||
slimbus_dbg(x); \
|
||||
if (dev->ipc_log_mask >= ERR_LEV) { \
|
||||
pr_err(x); \
|
||||
ipc_log_string(dev->ipc_slimbus_log, x); \
|
||||
dev->default_ipc_log_mask = dev->ipc_log_mask; \
|
||||
dev->ipc_log_mask = FATAL_LEV; \
|
||||
} \
|
||||
if (dev->ipc_log_mask == FATAL_LEV) { \
|
||||
ipc_log_string(dev->ipc_slimbus_log_err, x); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define SLIM_RST_LOGLVL(dev) { \
|
||||
dev->ipc_log_mask = dev->default_ipc_log_mask; \
|
||||
}
|
||||
|
||||
int slim_device_report_present(struct slim_controller *ctrl,
|
||||
struct slim_eaddr *e_addr, u8 *laddr);
|
||||
void slim_report_absent(struct slim_device *sbdev);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2018, Linaro Limited
|
||||
// Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
|
|
@ -48,42 +49,6 @@ static const struct segdist_code {
|
|||
{768, 2, 0xc02, 0x001},
|
||||
};
|
||||
|
||||
/*
|
||||
* Presence Rate table for all Natural Frequencies
|
||||
* The Presence rate of a constant bitrate stream is mean flow rate of the
|
||||
* stream expressed in occupied Segments of that Data Channel per second.
|
||||
* Table 66 from SLIMbus 2.0 Specs
|
||||
*
|
||||
* Index of the table corresponds to Presence rate code for the respective rate
|
||||
* in the table.
|
||||
*/
|
||||
static const int slim_presence_rate_table[] = {
|
||||
0, /* Not Indicated */
|
||||
12000,
|
||||
24000,
|
||||
48000,
|
||||
96000,
|
||||
192000,
|
||||
384000,
|
||||
768000,
|
||||
0, /* Reserved */
|
||||
110250,
|
||||
220500,
|
||||
441000,
|
||||
882000,
|
||||
176400,
|
||||
352800,
|
||||
705600,
|
||||
4000,
|
||||
8000,
|
||||
16000,
|
||||
32000,
|
||||
64000,
|
||||
128000,
|
||||
256000,
|
||||
512000,
|
||||
};
|
||||
|
||||
/**
|
||||
* slim_stream_allocate() - Allocate a new SLIMbus Stream
|
||||
* @dev:Slim device to be associated with
|
||||
|
|
@ -179,14 +144,49 @@ static int slim_deactivate_remove_channel(struct slim_stream_runtime *stream,
|
|||
|
||||
static int slim_get_prate_code(int rate)
|
||||
{
|
||||
int i;
|
||||
int ratem, ratefam, pr, exp = 0;
|
||||
bool done = false, exact = true;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(slim_presence_rate_table); i++) {
|
||||
if (rate == slim_presence_rate_table[i])
|
||||
return i;
|
||||
ratem = ((rate == SLIM_FREQ_441) || (rate == SLIM_FREQ_882)) ?
|
||||
(rate/SLIM_BASE_FREQ_11) : (rate/SLIM_BASE_FREQ_4);
|
||||
|
||||
ratefam = ((rate == SLIM_FREQ_441) || (rate == SLIM_FREQ_882)) ?
|
||||
2 : 1;
|
||||
|
||||
while (!done) {
|
||||
while ((ratem & 0x1) != 0x1) {
|
||||
ratem >>= 1;
|
||||
exp++;
|
||||
}
|
||||
if (ratem > 3) {
|
||||
ratem++;
|
||||
exact = false;
|
||||
} else {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
if (ratefam == 1) {
|
||||
if (ratem == 1) {
|
||||
pr = 0x10;
|
||||
} else {
|
||||
pr = 0;
|
||||
exp++;
|
||||
}
|
||||
} else {
|
||||
pr = 8;
|
||||
exp++;
|
||||
}
|
||||
|
||||
if (exp <= 7) {
|
||||
pr |= exp;
|
||||
if (exact)
|
||||
pr |= 0x80;
|
||||
} else {
|
||||
pr = 0;
|
||||
}
|
||||
|
||||
return pr;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -202,10 +202,16 @@ static int slim_get_prate_code(int rate)
|
|||
int slim_stream_prepare(struct slim_stream_runtime *rt,
|
||||
struct slim_stream_config *cfg)
|
||||
{
|
||||
struct slim_controller *ctrl = rt->dev->ctrl;
|
||||
struct slim_controller *ctrl;
|
||||
struct slim_port *port;
|
||||
int num_ports, i, port_id;
|
||||
|
||||
if (!rt || !cfg) {
|
||||
pr_err("%s: Stream or cfg is NULL, Check from client side\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ctrl = rt->dev->ctrl;
|
||||
if (rt->ports) {
|
||||
dev_err(&rt->dev->dev, "Stream already Prepared\n");
|
||||
return -EINVAL;
|
||||
|
|
@ -351,17 +357,27 @@ int slim_stream_enable(struct slim_stream_runtime *stream)
|
|||
{
|
||||
DEFINE_SLIM_BCAST_TXN(txn, SLIM_MSG_MC_BEGIN_RECONFIGURATION,
|
||||
3, SLIM_LA_MANAGER, NULL);
|
||||
struct slim_controller *ctrl = stream->dev->ctrl;
|
||||
struct slim_controller *ctrl;
|
||||
int ret, i;
|
||||
|
||||
if (!stream) {
|
||||
pr_err("%s: Stream is NULL, Check from client side\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ctrl = stream->dev->ctrl;
|
||||
if (ctrl->enable_stream) {
|
||||
mutex_lock(&ctrl->stream_lock);
|
||||
ret = ctrl->enable_stream(stream);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
mutex_unlock(&ctrl->stream_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < stream->num_ports; i++)
|
||||
stream->ports[i].ch.state = SLIM_CH_STATE_ACTIVE;
|
||||
|
||||
mutex_unlock(&ctrl->stream_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -404,11 +420,29 @@ int slim_stream_disable(struct slim_stream_runtime *stream)
|
|||
{
|
||||
DEFINE_SLIM_BCAST_TXN(txn, SLIM_MSG_MC_BEGIN_RECONFIGURATION,
|
||||
3, SLIM_LA_MANAGER, NULL);
|
||||
struct slim_controller *ctrl = stream->dev->ctrl;
|
||||
struct slim_controller *ctrl;
|
||||
int ret, i;
|
||||
|
||||
if (ctrl->disable_stream)
|
||||
ctrl->disable_stream(stream);
|
||||
if (!stream) {
|
||||
pr_err("%s: Stream is NULL, Check from client side\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!stream->ports || !stream->num_ports) {
|
||||
pr_err("%s: Stream port is NULL %d\n", __func__, stream->num_ports);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ctrl = stream->dev->ctrl;
|
||||
if (ctrl->disable_stream) {
|
||||
mutex_lock(&ctrl->stream_lock);
|
||||
ret = ctrl->disable_stream(stream);
|
||||
if (ret) {
|
||||
mutex_unlock(&ctrl->stream_lock);
|
||||
return ret;
|
||||
}
|
||||
mutex_unlock(&ctrl->stream_lock);
|
||||
}
|
||||
|
||||
ret = slim_do_transfer(ctrl, &txn);
|
||||
if (ret)
|
||||
|
|
@ -438,6 +472,16 @@ int slim_stream_unprepare(struct slim_stream_runtime *stream)
|
|||
{
|
||||
int i;
|
||||
|
||||
if (!stream) {
|
||||
pr_err("%s: Stream is NULL, Check from client side\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!stream->ports || !stream->num_ports) {
|
||||
pr_err("%s: Stream port is NULL %d\n", __func__, stream->num_ports);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < stream->num_ports; i++)
|
||||
slim_disconnect_port(stream, &stream->ports[i]);
|
||||
|
||||
|
|
@ -507,8 +551,14 @@ EXPORT_SYMBOL(slim_stream_unprepare_disconnect_port);
|
|||
*/
|
||||
int slim_stream_free(struct slim_stream_runtime *stream)
|
||||
{
|
||||
struct slim_device *sdev = stream->dev;
|
||||
struct slim_device *sdev;
|
||||
|
||||
if (!stream) {
|
||||
pr_err("%s: Stream is NULL, Check from client side\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sdev = stream->dev;
|
||||
spin_lock(&sdev->stream_list_lock);
|
||||
list_del(&stream->node);
|
||||
spin_unlock(&sdev->stream_list_lock);
|
||||
|
|
|
|||
48
drivers/slimbus/trace.h
Normal file
48
drivers/slimbus/trace.h
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* trace.h - Slimbus Controller Trace Support
|
||||
*
|
||||
* Copyright (C) 2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM slimbus
|
||||
|
||||
#if !defined(__SLIMBUS_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
|
||||
#define __SLIMBUS_TRACE_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/tracepoint.h>
|
||||
#include <asm/byteorder.h>
|
||||
#define MAX_MSG_LEN 100
|
||||
|
||||
TRACE_EVENT(slimbus_dbg,
|
||||
TP_PROTO(const char *func, struct va_format *vaf),
|
||||
TP_ARGS(func, vaf),
|
||||
TP_STRUCT__entry(
|
||||
__string(func, func)
|
||||
__dynamic_array(char, msg, MAX_MSG_LEN)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__assign_str(func, func);
|
||||
WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg),
|
||||
MAX_MSG_LEN, vaf->fmt,
|
||||
*vaf->va) >= MAX_MSG_LEN);
|
||||
),
|
||||
TP_printk("%s: %s", __get_str(func), __get_str(msg))
|
||||
);
|
||||
|
||||
#endif /* __SLIMBUS_TRACE_H */
|
||||
|
||||
/* this part has to be here */
|
||||
|
||||
#undef TRACE_INCLUDE_PATH
|
||||
#define TRACE_INCLUDE_PATH .
|
||||
|
||||
#undef TRACE_INCLUDE_FILE
|
||||
#define TRACE_INCLUDE_FILE trace
|
||||
|
||||
/* This part must be outside protection */
|
||||
#include <trace/define_trace.h>
|
||||
Loading…
Reference in New Issue
Block a user