slimbus: qcom-ngd-ctrl: snapshot of slimbus ngd driver

slimbus driver snapshot from msm-5.15 branch
'commit 559e4f28f215 ("Merge "soc: qcom:
Add v19 support for socinfo"")'.

Change-Id: Ie26ee41da0e68f0265b26dc2a603771e8bd27ff6
Signed-off-by: Chandana Kishori Chiluveru <quic_cchiluve@quicinc.com>
This commit is contained in:
Chandana Kishori Chiluveru 2022-11-22 09:19:51 -08:00 committed by Gerrit - the friendly Code Review server
parent f47fcb8096
commit 1c9f4ac773
6 changed files with 963 additions and 148 deletions

View File

@ -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",

View File

@ -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

View File

@ -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);

View File

@ -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
View 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>