mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
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:
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
};
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user