Merge commit '82ac6d206e0f1e202322e5fe99aee0b241fe33c1'

* commit '82ac6d206e0f1e202322e5fe99aee0b241fe33c1':
  ASoC: rockchip: i2s-tdm: Add support for FSXN Control
  video: rockchip: rga3: using async mode to print log when async is disabled
  video: rockchip: rga3: fix RGA3 state has been cleared in IRQ
  video: rockchip: rga3: rga3 support read_status ops
  ASoC: rockchip: multi-dais: Add support for TRCM
  ASoC: rockchip: i2s-tdm: Fix TRCM panic on Multi Dais
  phy: rockchip: inno-usb2: Support usb wakeup system for rk3576
  drm/rockchip: gem: Fix alloc size setting for IOMMU device
  PCI: dw: rockchip: Record the rasdes capability offset
  ARM: dts: rockchip: rk3506 boards: Modify can init freq to 300M.
  ARM: dts: rockchip: rk3506: assign default clock rate for can

Change-Id: I2d02839fac0021edd97f7372a1dee552e64a773a
This commit is contained in:
Tao Huang
2024-11-26 19:41:03 +08:00
14 changed files with 356 additions and 58 deletions

View File

@@ -60,7 +60,7 @@
&can0 {
assigned-clocks = <&cru CLK_CAN0>;
assigned-clock-rates = <200000000>;
assigned-clock-rates = <300000000>;
pinctrl-0 = <&rm_io30_can0_tx &rm_io31_can0_rx>;
pinctrl-names = "default";
status = "disabled";

View File

@@ -47,6 +47,8 @@
clock-names = "baudclk", "apb_pclk";
resets = <&cru SRST_CAN0>, <&cru SRST_H_CAN0>;
reset-names = "can", "can-apb";
assigned-clocks = <&cru CLK_CAN0>;
assigned-clock-rates = <300000000>;
status = "disabled";
};
@@ -58,6 +60,8 @@
clock-names = "baudclk", "apb_pclk";
resets = <&cru SRST_CAN1>, <&cru SRST_H_CAN1>;
reset-names = "can", "can-apb";
assigned-clocks = <&cru CLK_CAN1>;
assigned-clock-rates = <300000000>;
status = "disabled";
};

View File

@@ -225,7 +225,7 @@
&can0 {
assigned-clocks = <&cru CLK_CAN0>;
assigned-clock-rates = <200000000>;
assigned-clock-rates = <300000000>;
pinctrl-0 = <&rm_io27_can0_tx &rm_io28_can0_rx>;
pinctrl-names = "default";
status = "okay";

View File

@@ -67,6 +67,8 @@ static int rockchip_gem_iommu_map(struct rockchip_gem_object *rk_obj)
iommu_flush_iotlb_all(private->domain);
rk_obj->size = ret;
return 0;
err_remove_node:
@@ -648,6 +650,15 @@ rockchip_gem_create_object(struct drm_device *drm, unsigned int size,
if (ret)
goto err_free_rk_obj;
/**
* For iommu device, this size will be set in rockchip_gem_iommu_map().
* The actual mapped size may be larger than the request size.
*
* For non-iommu device, set to the requested fb size.
*/
if (rk_obj->size == 0)
rk_obj->size = size;
return rk_obj;
err_free_rk_obj:
@@ -728,7 +739,6 @@ rockchip_gem_create_with_handle(struct drm_file *file_priv,
return ERR_CAST(rk_obj);
obj = &rk_obj->base;
rk_obj->size = size;
/*
* allocate a id of idr table where the obj is registered

View File

@@ -141,7 +141,6 @@ struct rk_pcie {
bool hp_no_link;
bool is_lpbk;
bool is_comp;
bool have_rasdes;
bool finish_probe;
struct regulator *vpcie3v3;
struct irq_domain *irq_domain;
@@ -159,6 +158,7 @@ struct rk_pcie {
u32 slot_power_limit;
u8 slot_power_limit_value;
u8 slot_power_limit_scale;
u32 rasdes_off;
};
struct rk_pcie_of_data {
@@ -1044,11 +1044,7 @@ static int rockchip_pcie_rasdes_show(struct seq_file *s, void *unused)
seq_printf(s, "Common event signal status: 0x%s\n", pm);
cap_base = dw_pcie_find_ext_capability(pcie->pci, PCI_EXT_CAP_ID_VNDR);
if (!cap_base) {
dev_err(pcie->pci->dev, "Not able to find RASDES CAP!\n");
return 0;
}
cap_base = pcie->rasdes_off;
RAS_DES_EVENT("EBUF Overflow: ", 0);
RAS_DES_EVENT("EBUF Under-run: ", 0x0010000);
@@ -1099,11 +1095,7 @@ static ssize_t rockchip_pcie_rasdes_write(struct file *file,
if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
return -EFAULT;
cap_base = dw_pcie_find_ext_capability(pcie->pci, PCI_EXT_CAP_ID_VNDR);
if (!cap_base) {
dev_err(pcie->pci->dev, "Not able to find RASDES CAP!\n");
return 0;
}
cap_base = pcie->rasdes_off;
if (!strncmp(buf, "enable", 6)) {
dev_info(pcie->pci->dev, "RAS DES Event: Enable ALL!\n");
@@ -1137,11 +1129,7 @@ static int rockchip_pcie_fault_inject_show(struct seq_file *s, void *unused)
struct rk_pcie *pcie = s->private;
u32 cap_base;
cap_base = dw_pcie_find_ext_capability(pcie->pci, PCI_EXT_CAP_ID_VNDR);
if (!cap_base) {
dev_err(pcie->pci->dev, "Not able to find RASDES CAP!\n");
return -EINVAL;
}
cap_base = pcie->rasdes_off;
INJECTION_EVENT("ERROR_INJECTION0_ENABLE: ", 0x30, 1, 0);
INJECTION_EVENT("ERROR_INJECTION1_ENABLE: ", 0x30, 1, 1);
@@ -1222,11 +1210,7 @@ static ssize_t rockchip_pcie_fault_inject_write(struct file *file,
if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, cnt)))
return -EFAULT;
cap_base = dw_pcie_find_ext_capability(pcie->pci, PCI_EXT_CAP_ID_VNDR);
if (!cap_base) {
dev_err(dev, "Not able to find RASDES CAP!\n");
return -EINVAL;
}
cap_base = pcie->rasdes_off;
if (sscanf(buf, "%d %d %d %d", &einj, &enable, &type, &count) < 4) {
dev_err(dev,
@@ -1301,7 +1285,7 @@ static int rockchip_pcie_debugfs_init(struct rk_pcie *pcie)
{
struct dentry *file;
if (!IS_ENABLED(CONFIG_DEBUG_FS) || !pcie->have_rasdes)
if (!IS_ENABLED(CONFIG_DEBUG_FS) || !pcie->rasdes_off)
return 0;
pcie->debugfs = debugfs_create_dir(dev_name(pcie->pci->dev), NULL);
@@ -1542,13 +1526,13 @@ static int rk_pcie_host_config(struct rk_pcie *rk_pcie)
}
/* Enable RASDES Error event by default */
val = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_VNDR);
if (!val) {
if (!rk_pcie->in_suspend)
rk_pcie->rasdes_off = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_VNDR);
if (!rk_pcie->rasdes_off) {
dev_err(pci->dev, "Unable to find RASDES CAP!\n");
} else {
dw_pcie_writel_dbi(pci, val + 8, 0x1c);
dw_pcie_writel_dbi(pci, val + 8, 0x3);
rk_pcie->have_rasdes = true;
dw_pcie_writel_dbi(pci, rk_pcie->rasdes_off + 8, 0x1c);
dw_pcie_writel_dbi(pci, rk_pcie->rasdes_off + 8, 0x3);
}
dw_pcie_dbi_ro_wr_en(pci);

View File

@@ -215,11 +215,13 @@ struct rockchip_usb2phy_port_cfg {
* @clkout_ctl_phy: keep on/turn off output clk of phy via phy inner
* debug register.
* @ls_filter_con: set linestate filter time.
* @port_cfgs: usb-phy port configurations.
* @ls_filter_con: set linestate filter time.
* @refclk_fsel: reference clock frequency select,
* true - select 24 MHz
* false - select 26 MHz
* @detclk_sel: usb phy grf reference clock select,
* true - select OSC clock
* false - select pclk
* @port_cfgs: usb-phy port configurations.
* @chg_det: charger detection registers.
*/
struct rockchip_usb2phy_cfg {
@@ -233,6 +235,7 @@ struct rockchip_usb2phy_cfg {
struct usb2phy_reg clkout_ctl_phy;
struct usb2phy_reg ls_filter_con;
struct usb2phy_reg refclk_fsel;
struct usb2phy_reg detclk_sel;
const struct rockchip_usb2phy_port_cfg port_cfgs[USB2PHY_NUM_PORTS];
const struct rockchip_chg_det_reg chg_det;
};
@@ -3327,6 +3330,13 @@ static int rockchip_usb2phy_pm_suspend(struct device *dev)
if (wakeup_enable && rphy->irq > 0)
enable_irq_wake(rphy->irq);
/*
* Select the usb2 phy interrupt logic clock from OSC clock
* to support interrupt detection if VD_LOGIC is powerdown.
*/
if (phy_cfg->detclk_sel.enable)
property_enable(rphy->grf, &phy_cfg->detclk_sel, true);
return ret;
}
@@ -3361,6 +3371,9 @@ static int rockchip_usb2phy_pm_resume(struct device *dev)
dev_err(rphy->dev, "failed to set ls filter %d\n", ret);
}
if (phy_cfg->detclk_sel.enable)
property_enable(rphy->grf, &phy_cfg->detclk_sel, false);
for (index = 0; index < phy_cfg->num_ports; index++) {
rport = &rphy->ports[index];
if (!rport->phy)
@@ -4275,8 +4288,9 @@ static const struct rockchip_usb2phy_cfg rk3576_phy_cfgs[] = {
.num_ports = 1,
.phy_tuning = rk3576_usb2phy_tuning,
.clkout_ctl = { 0x0008, 0, 0, 1, 0 },
.ls_filter_con = { 0x0020, 19, 0, 0x30100, 0x00020 },
.ls_filter_con = { 0x0020, 19, 0, 0x30100, 0x06020 },
.refclk_fsel = { 0x0004, 2, 0, 0x6, 0x2 },
.detclk_sel = { 0x00d0, 0, 0, 0, 1 },
.port_cfgs = {
[USB2PHY_PORT_OTG] = {
.phy_sus = { 0x0000, 8, 0, 0, 0x1d1 },
@@ -4330,8 +4344,9 @@ static const struct rockchip_usb2phy_cfg rk3576_phy_cfgs[] = {
.num_ports = 1,
.phy_tuning = rk3576_usb2phy_tuning,
.clkout_ctl = { 0x2008, 0, 0, 1, 0 },
.ls_filter_con = { 0x2020, 19, 0, 0x30100, 0x00020 },
.ls_filter_con = { 0x2020, 19, 0, 0x30100, 0x06020 },
.refclk_fsel = { 0x2004, 2, 0, 0x6, 0x2 },
.detclk_sel = { 0x20d0, 0, 0, 0, 1 },
.port_cfgs = {
[USB2PHY_PORT_OTG] = {
.phy_sus = { 0x2000, 8, 0, 0, 0x1d1 },

View File

@@ -58,12 +58,12 @@ static inline int rga_dma_fence_get_status(struct dma_fence *fence)
#else
static inline struct dma_fence *rga_dma_fence_alloc(void)
{
return NULL;
return ERR_PTR(-EINVAL);
}
static inline int rga_dma_fence_get_fd(struct dma_fence *fence)
{
return 0;
return -1;
}
static inline struct dma_fence *rga_get_dma_fence_from_fd(int fence_fd)
@@ -80,7 +80,7 @@ static inline int rga_dma_fence_add_callback(struct dma_fence *fence,
dma_fence_func_t func,
void *private)
{
return 0;
return -EINVAL;
}
static inline void rga_dma_fence_put(struct dma_fence *fence)
@@ -93,7 +93,7 @@ static inline void rga_dma_fence_signal(struct dma_fence *fence, int error)
static inline int rga_dma_fence_get_status(struct dma_fence *fence)
{
return 0;
return -EINVAL;
}
#endif /* #ifdef CONFIG_SYNC_FILE */

View File

@@ -2151,23 +2151,41 @@ static int rga3_get_version(struct rga_scheduler_t *scheduler)
return 0;
}
static int rga3_read_status(struct rga_job *job, struct rga_scheduler_t *scheduler)
{
job->intr_status = rga_read(RGA3_INT_RAW, scheduler);
job->hw_status = rga_read(RGA3_STATUS0, scheduler);
job->cmd_status = rga_read(RGA3_CMD_STATE, scheduler);
job->work_cycle = 0;
return 0;
}
static void rga3_clear_intr(struct rga_scheduler_t *scheduler)
{
rga_write(m_RGA3_INT_FRM_DONE | m_RGA3_INT_CMD_LINE_FINISH | m_RGA3_INT_ERROR_MASK,
RGA3_INT_CLR, scheduler);
}
static int rga3_irq(struct rga_scheduler_t *scheduler)
{
struct rga_job *job = scheduler->running_job;
/*clear INTR */
rga_write(m_RGA3_INT_FRM_DONE | m_RGA3_INT_CMD_LINE_FINISH | m_RGA3_INT_ERROR_MASK,
RGA3_INT_CLR, scheduler);
if (job == NULL) {
rga3_clear_intr(scheduler);
rga_err("core[%d], invalid job, INTR[0x%x], HW_STATUS[0x%x], CMD_STATUS[0x%x]\n",
scheduler->core, rga_read(RGA3_INT_RAW, scheduler),
rga_read(RGA3_STATUS0, scheduler), rga_read(RGA3_CMD_STATE, scheduler));
if (job == NULL)
return IRQ_HANDLED;
}
if (test_bit(RGA_JOB_STATE_INTR_ERR, &job->state))
if (test_bit(RGA_JOB_STATE_INTR_ERR, &job->state)) {
rga3_clear_intr(scheduler);
return IRQ_WAKE_THREAD;
}
job->intr_status = rga_read(RGA3_INT_RAW, scheduler);
job->hw_status = rga_read(RGA3_STATUS0, scheduler);
job->cmd_status = rga_read(RGA3_CMD_STATE, scheduler);
scheduler->ops->read_status(job, scheduler);
if (DEBUGGER_EN(INT_FLAG))
rga_job_log(job, "irq handler, INTR[0x%x], HW_STATUS[0x%x], CMD_STATUS[0x%x]\n",
@@ -2183,6 +2201,8 @@ static int rga3_irq(struct rga_scheduler_t *scheduler)
scheduler->ops->soft_reset(scheduler);
}
rga3_clear_intr(scheduler);
return IRQ_WAKE_THREAD;
}
@@ -2224,7 +2244,7 @@ const struct rga_backend_ops rga3_ops = {
.init_reg = rga3_init_reg,
.soft_reset = rga3_soft_reset,
.read_back_reg = NULL,
.read_status = NULL,
.read_status = rga3_read_status,
.irq = rga3_irq,
.isr_thread = rga3_isr_thread,
};

View File

@@ -936,6 +936,13 @@ static long rga_ioctl(struct file *file, uint32_t cmd, unsigned long arg)
return -EBUSY;
}
if (cmd == RGA_BLIT_ASYNC && !IS_ENABLED(CONFIG_ROCKCHIP_RGA_ASYNC)) {
rga_log("The current driver does not support asynchronous mode, please enable CONFIG_ROCKCHIP_RGA_ASYNC.\n");
up_read(&rga_drvdata->rwsem);
return -EINVAL;
}
switch (cmd) {
case RGA_BLIT_SYNC:
case RGA_BLIT_ASYNC:

View File

@@ -270,6 +270,7 @@ struct rga_job *rga_job_done(struct rga_scheduler_t *scheduler)
static int rga_job_timeout_query_state(struct rga_job *job, int orig_ret)
{
int ret = orig_ret;
struct rga_scheduler_t *scheduler = job->scheduler;
if (test_bit(RGA_JOB_STATE_DONE, &job->state) &&
@@ -279,7 +280,7 @@ static int rga_job_timeout_query_state(struct rga_job *job, int orig_ret)
test_bit(RGA_JOB_STATE_FINISH, &job->state)) {
rga_job_err(job, "job hardware has finished, but the software has timeout!\n");
return -EBUSY;
ret = -EBUSY;
} else if (!test_bit(RGA_JOB_STATE_DONE, &job->state) &&
!test_bit(RGA_JOB_STATE_FINISH, &job->state)) {
rga_job_err(job, "job hardware has timeout.\n");
@@ -287,7 +288,7 @@ static int rga_job_timeout_query_state(struct rga_job *job, int orig_ret)
if (scheduler->ops->read_status)
scheduler->ops->read_status(job, scheduler);
return -EBUSY;
ret = -EBUSY;
}
rga_job_err(job, "timeout core[%d]: INTR[0x%x], HW_STATUS[0x%x], CMD_STATUS[0x%x], WORK_CYCLE[0x%x(%d)]\n",
@@ -295,7 +296,7 @@ static int rga_job_timeout_query_state(struct rga_job *job, int orig_ret)
job->intr_status, job->hw_status, job->cmd_status,
job->work_cycle, job->work_cycle);
return orig_ret;
return ret;
}
static void rga_job_scheduler_timeout_clean(struct rga_scheduler_t *scheduler)
@@ -1253,9 +1254,9 @@ int rga_request_submit(struct rga_request *request)
if (request->sync_mode == RGA_BLIT_ASYNC) {
release_fence = rga_dma_fence_alloc();
if (IS_ERR(release_fence)) {
if (IS_ERR_OR_NULL(release_fence)) {
rga_req_err(request, "Can not alloc release fence!\n");
ret = IS_ERR(release_fence);
ret = IS_ERR(release_fence) ? PTR_ERR(release_fence) : -EINVAL;
goto err_reset_request;
}
request->release_fence = release_fence;

View File

@@ -138,6 +138,7 @@ struct rk_i2s_tdm_dev {
bool tdm_mode;
bool tdm_fsync_half_frame;
bool is_dma_active[SNDRV_PCM_STREAM_LAST + 1];
bool no_pcm;
unsigned int mclk_rx_freq;
unsigned int mclk_tx_freq;
unsigned int mclk_root0_freq;
@@ -162,6 +163,8 @@ struct rk_i2s_tdm_dev {
#ifdef CONFIG_SND_SOC_ROCKCHIP_I2S_TDM_MULTI_LANES
struct snd_soc_dai *clk_src_dai;
struct gpio_desc *tdm_fsync_gpio;
struct gpio_desc *fsxn_tx_gpio;
struct gpio_desc *fsxn_rx_gpio;
unsigned int tx_lanes;
unsigned int rx_lanes;
void __iomem *clk_src_base;
@@ -183,6 +186,20 @@ static struct i2s_of_quirks {
},
};
static int rockchip_trcm_dma_guard_ctrl(struct rk_i2s_tdm_dev *i2s_tdm,
int stream, bool en)
{
if (i2s_tdm->no_pcm)
return 0;
if (!i2s_tdm->pcm_comp) {
dev_err(i2s_tdm->dev, "Uninitialized component for TRCM\n");
return -EINVAL;
}
return dmaengine_trcm_dma_guard_ctrl(i2s_tdm->pcm_comp, stream, en);
}
static bool rockchip_i2s_tdm_stream_valid(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
@@ -799,11 +816,58 @@ static int rockchip_i2s_tdm_multi_lanes_set_clk(struct snd_pcm_substream *substr
return 0;
}
static int rockchip_i2s_tdm_fsxn_start(struct rk_i2s_tdm_dev *i2s_tdm, int stream)
{
struct gpio_desc *fsn;
unsigned int msk, val;
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
fsn = i2s_tdm->fsxn_tx_gpio;
msk = I2S_XFER_TXS_MASK;
val = I2S_XFER_TXS_START;
} else {
fsn = i2s_tdm->fsxn_rx_gpio;
msk = I2S_XFER_RXS_MASK;
val = I2S_XFER_RXS_START;
}
if (!fsn)
return -ENODEV;
regmap_update_bits(i2s_tdm->regmap, I2S_XFER, msk, val);
udelay(10);
gpiod_set_value(fsn, 1);
return 0;
}
static int rockchip_i2s_tdm_fsxn_stop(struct rk_i2s_tdm_dev *i2s_tdm, int stream)
{
struct gpio_desc *fsn;
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
fsn = i2s_tdm->fsxn_tx_gpio;
else
fsn = i2s_tdm->fsxn_rx_gpio;
if (!fsn)
return -ENODEV;
gpiod_set_value(fsn, 0);
return 0;
}
static int rockchip_i2s_tdm_multi_lanes_start(struct rk_i2s_tdm_dev *i2s_tdm, int stream)
{
unsigned int tdm_h = 0, tdm_l = 0, i2s_h = 0, i2s_l = 0;
unsigned int msk, val, reg, fmt;
unsigned long flags;
int ret;
ret = rockchip_i2s_tdm_fsxn_start(i2s_tdm, stream);
if (ret == 0)
return 0;
if (!i2s_tdm->tdm_fsync_gpio || !i2s_tdm->i2s_lrck_gpio)
return -ENOSYS;
@@ -906,6 +970,25 @@ static int rockchip_i2s_tdm_multi_lanes_parse(struct rk_i2s_tdm_dev *i2s_tdm)
i2s_tdm->rx_lanes = val;
}
i2s_tdm->fsxn_rx_gpio = devm_gpiod_get_optional(i2s_tdm->dev, "fsxn-rx",
GPIOD_OUT_LOW);
if (IS_ERR(i2s_tdm->fsxn_rx_gpio)) {
ret = PTR_ERR(i2s_tdm->fsxn_rx_gpio);
dev_err(i2s_tdm->dev, "Failed to get fsxn_rx_gpio %d\n", ret);
return ret;
}
i2s_tdm->fsxn_tx_gpio = devm_gpiod_get_optional(i2s_tdm->dev, "fsxn-tx",
GPIOD_OUT_LOW);
if (IS_ERR(i2s_tdm->fsxn_tx_gpio)) {
ret = PTR_ERR(i2s_tdm->fsxn_tx_gpio);
dev_err(i2s_tdm->dev, "Failed to get fsxn_tx_gpio %d\n", ret);
return ret;
}
if (i2s_tdm->fsxn_rx_gpio || i2s_tdm->fsxn_tx_gpio)
dev_info(i2s_tdm->dev, "FSXN Mode\n");
/* It's optional, required when use soc clk src, such as: i2s2_2ch */
clk_src_node = of_parse_phandle(i2s_tdm->dev->of_node, "rockchip,clk-src", 0);
gpiod_flags = clk_src_node ? GPIOD_ASIS : GPIOD_IN;
@@ -1084,6 +1167,10 @@ static void rockchip_i2s_tdm_xfer_stop(struct rk_i2s_tdm_dev *i2s_tdm,
rockchip_i2s_tdm_clear(i2s_tdm, clr);
#ifdef CONFIG_SND_SOC_ROCKCHIP_I2S_TDM_MULTI_LANES
rockchip_i2s_tdm_fsxn_stop(i2s_tdm, stream);
#endif
dev_dbg(i2s_tdm->dev, "%s: stream: %d force: %d\n",
__func__, stream, force);
}
@@ -1100,7 +1187,7 @@ static void rockchip_i2s_tdm_xfer_trcm_start(struct rk_i2s_tdm_dev *i2s_tdm,
regmap_read(i2s_tdm->regmap, I2S_DMACR, &val);
en = I2S_DMACR_RDE(1) | I2S_DMACR_TDE(1);
if ((val & en) != en) {
dmaengine_trcm_dma_guard_ctrl(i2s_tdm->pcm_comp, bstream, 1);
rockchip_trcm_dma_guard_ctrl(i2s_tdm, bstream, 1);
rockchip_i2s_tdm_dma_ctrl(i2s_tdm, bstream, 1);
}
rockchip_i2s_tdm_xfer_start(i2s_tdm, 0);
@@ -1127,7 +1214,7 @@ static void rockchip_i2s_tdm_trcm_pause(struct snd_pcm_substream *substream,
int bstream = SNDRV_PCM_STREAM_LAST - stream;
if (i2s_tdm->pcm_comp)
dmaengine_trcm_dma_guard_ctrl(i2s_tdm->pcm_comp, stream, 0);
rockchip_trcm_dma_guard_ctrl(i2s_tdm, stream, 0);
/* store the current state, prepare for resume if necessary */
i2s_tdm->is_dma_active[bstream] = is_dma_active(i2s_tdm, bstream);
@@ -1145,7 +1232,7 @@ static void rockchip_i2s_tdm_trcm_resume(struct snd_pcm_substream *substream,
int bstream = SNDRV_PCM_STREAM_LAST - substream->stream;
if (i2s_tdm->pcm_comp) {
dmaengine_trcm_dma_guard_ctrl(i2s_tdm->pcm_comp, stream, 1);
rockchip_trcm_dma_guard_ctrl(i2s_tdm, stream, 1);
rockchip_i2s_tdm_dma_ctrl(i2s_tdm, stream, 1);
}
@@ -3005,6 +3092,7 @@ static int rockchip_i2s_tdm_register_platform(struct device *dev)
int ret = 0;
if (device_property_read_bool(dev, "rockchip,no-dmaengine")) {
i2s_tdm->no_pcm = true;
dev_info(dev, "Used for Multi-DAI\n");
return 0;
}
@@ -3049,8 +3137,8 @@ static int __maybe_unused i2s_tdm_runtime_suspend(struct device *dev)
if (i2s_tdm->pcm_comp && i2s_tdm->clk_trcm) {
rockchip_i2s_tdm_dma_ctrl(i2s_tdm, 0, 0);
rockchip_i2s_tdm_dma_ctrl(i2s_tdm, 1, 0);
dmaengine_trcm_dma_guard_ctrl(i2s_tdm->pcm_comp, 0, 0);
dmaengine_trcm_dma_guard_ctrl(i2s_tdm->pcm_comp, 1, 0);
rockchip_trcm_dma_guard_ctrl(i2s_tdm, 0, 0);
rockchip_trcm_dma_guard_ctrl(i2s_tdm, 1, 0);
}
regcache_cache_only(i2s_tdm->regmap, true);

View File

@@ -25,6 +25,9 @@
#define SOUND_NAME_PREFIX "sound-name-prefix"
#define I2S_CKR 0x8
#define IS_I2S_TRCM(v) ((v) & GENMASK(29, 28))
static inline struct rk_mdais_dev *to_info(struct snd_soc_dai *dai)
{
return snd_soc_dai_get_drvdata(dai);
@@ -515,7 +518,7 @@ static int rockchip_mdais_probe(struct platform_device *pdev)
struct device_node *node;
struct snd_soc_dai_driver *soc_dai;
struct rk_dai *dais;
unsigned int *map;
unsigned int *map, val;
int count, mp_count;
int ret = 0, i = 0;
@@ -575,6 +578,11 @@ static int rockchip_mdais_probe(struct platform_device *pdev)
dais[i].dai = rockchip_mdais_find_dai(node);
if (!dais[i].dai)
return -EPROBE_DEFER;
if (strstr(dev_driver_string(dais[i].dai->dev), "i2s")) {
val = snd_soc_component_read(dais[i].dai->component, I2S_CKR);
dais[i].trcm = IS_I2S_TRCM(val);
}
}
mdais_parse_daifmt(np, dais, count);

View File

@@ -17,6 +17,7 @@ struct rk_dai {
struct snd_soc_dai *dai;
unsigned int fmt;
unsigned int fmt_msk;
bool trcm;
};
struct rk_mdais_dev {

View File

@@ -18,6 +18,8 @@
#include "rockchip_multi_dais.h"
#include "rockchip_dlp.h"
#define DMA_GUARD_BUFFER_SIZE 64
#define I2S_TXFIFOLR 0xc
#define I2S_RXFIFOLR 0x2c
#define SAI_TXFIFOLR 0x1c
@@ -43,11 +45,19 @@ static unsigned int prealloc_buffer_size_kbytes = 512;
module_param(prealloc_buffer_size_kbytes, uint, 0444);
MODULE_PARM_DESC(prealloc_buffer_size_kbytes, "Preallocate DMA buffer size (KB).");
struct trcm_dma_guard {
dma_addr_t dma_addr;
unsigned char *dma_area;
};
struct dmaengine_mpcm {
struct dlp dlp;
struct rk_mdais_dev *mdais;
struct dma_chan *tx_chans[MAX_DAIS];
struct dma_chan *rx_chans[MAX_DAIS];
struct trcm_dma_guard tx_guards[MAX_DAIS];
struct trcm_dma_guard rx_guards[MAX_DAIS];
bool guard;
};
struct dmaengine_mpcm_runtime_data {
@@ -484,6 +494,73 @@ static void dmaengine_mpcm_dlp_stop(struct snd_soc_component *component,
dlp_stop(component, substream, dmaengine_mpcm_raw_pointer);
}
static int dmaengine_mpcm_trcm_dma_guard_ctrl(struct snd_soc_component *component,
int stream, bool en)
{
struct dmaengine_mpcm *pcm = soc_component_to_mpcm(component);
struct dma_chan **chans;
struct trcm_dma_guard *guards;
struct rk_dai *dais;
struct dma_async_tx_descriptor *desc;
enum dma_transfer_direction direction;
unsigned int *maps, buf_sz;
int i, ret, num;
if (!pcm->guard)
return 0;
dais = pcm->mdais->dais;
num = pcm->mdais->num_dais;
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
chans = pcm->tx_chans;
guards = pcm->tx_guards;
direction = DMA_MEM_TO_DEV;
maps = pcm->mdais->playback_channel_maps;
} else {
chans = pcm->rx_chans;
guards = pcm->rx_guards;
direction = DMA_DEV_TO_MEM;
maps = pcm->mdais->capture_channel_maps;
}
if (!en) {
for (i = 0; i < num; i++) {
if (!chans[i] || !dais[i].trcm || !maps[i])
continue;
ret = dmaengine_terminate_all(chans[i]);
if (ret)
return ret;
}
return 0;
}
for (i = 0; i < num; i++) {
if (!chans[i] || !dais[i].trcm || !maps[i])
continue;
buf_sz = DMA_GUARD_BUFFER_SIZE / (maps[i] * 4);
buf_sz = buf_sz * maps[i] * 4;
if (!buf_sz)
return -EINVAL;
desc = dmaengine_prep_dma_cyclic(chans[i], guards[i].dma_addr,
buf_sz, buf_sz, direction,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc)
return -ENOMEM;
desc->callback = NULL;
desc->callback_param = NULL;
dmaengine_submit(desc);
dma_async_issue_pending(chans[i]);
}
return 0;
}
static int dmaengine_mpcm_trigger(struct snd_soc_component *component,
struct snd_pcm_substream *substream, int cmd)
{
@@ -504,6 +581,7 @@ static int dmaengine_mpcm_trigger(struct snd_soc_component *component,
mpcm_dma_async_issue_pending(prtd);
}
#endif
mpcm_dmaengine_terminate_all(prtd);
ret = dmaengine_mpcm_prepare_and_submit(substream);
if (ret)
return ret;
@@ -530,6 +608,7 @@ static int dmaengine_mpcm_trigger(struct snd_soc_component *component,
case SNDRV_PCM_TRIGGER_STOP:
dmaengine_mpcm_dlp_stop(component, substream);
mpcm_dmaengine_terminate_all(prtd);
dmaengine_mpcm_trcm_dma_guard_ctrl(component, substream->stream, 1);
prtd->start_flag = false;
break;
default:
@@ -725,6 +804,82 @@ static int dmaengine_mpcm_open(struct snd_soc_component *component,
return 0;
}
static int dmaengine_mpcm_trcm_dma_guard_new(struct snd_soc_component *component,
struct snd_soc_pcm_runtime *rtd)
{
struct dmaengine_mpcm *pcm = soc_component_to_mpcm(component);
struct dma_chan **chans;
struct trcm_dma_guard *guards;
struct rk_dai *dais;
struct snd_dmaengine_dai_dma_data *dma_data;
struct snd_pcm_substream *substream;
struct dma_slave_config slave_config;
struct device *dev;
dma_addr_t dma_addr;
unsigned char *dma_area;
int i, j, ret, num;
dais = pcm->mdais->dais;
num = pcm->mdais->num_dais;
for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) {
substream = rtd->pcm->streams[i].substream;
if (!substream)
continue;
dev = dmaengine_dma_dev(pcm, substream);
chans = substream->stream ? pcm->rx_chans : pcm->tx_chans;
guards = substream->stream ? pcm->rx_guards : pcm->tx_guards;
for (j = 0; j < num; j++) {
if (!chans[j] || !dais[j].trcm)
continue;
pcm->guard = true;
dma_area = dma_alloc_coherent(dev, DMA_GUARD_BUFFER_SIZE,
&dma_addr, GFP_KERNEL);
if (!dma_area)
return -ENOMEM;
memset(dma_area, 0x0, DMA_GUARD_BUFFER_SIZE);
guards[j].dma_addr = dma_addr;
guards[j].dma_area = dma_area;
memset(&slave_config, 0, sizeof(slave_config));
dma_data = snd_soc_dai_get_dma_data(dais[j].dai, substream);
if (!dma_data)
continue;
snd_dmaengine_mpcm_set_config_from_dai_data(substream,
dma_data,
&slave_config);
/*
* Use the max-16w to cover all 2^n cases, maybe better
* per channels and fmt, at the moment, we use the simple
* way.
*/
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
slave_config.direction = DMA_MEM_TO_DEV;
slave_config.dst_maxburst = 16;
} else {
slave_config.direction = DMA_DEV_TO_MEM;
slave_config.src_maxburst = 16;
}
ret = dmaengine_slave_config(chans[j], &slave_config);
if (ret)
return ret;
}
}
return 0;
}
static int dmaengine_mpcm_new(struct snd_soc_component *component, struct snd_soc_pcm_runtime *rtd)
{
struct dmaengine_mpcm *pcm = soc_component_to_mpcm(component);
@@ -733,10 +888,15 @@ static int dmaengine_mpcm_new(struct snd_soc_component *component, struct snd_so
size_t prealloc_buffer_size;
size_t max_buffer_size;
unsigned int i;
int ret;
prealloc_buffer_size = prealloc_buffer_size_kbytes * 1024;
max_buffer_size = SIZE_MAX;
ret = dmaengine_mpcm_trcm_dma_guard_new(component, rtd);
if (ret)
return ret;
for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) {
substream = rtd->pcm->streams[i].substream;
if (!substream)