mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
Merge commit 'ffd1dbd70cc94d0f7e35cec54e47fa477958699d'
* commit 'ffd1dbd70cc94d0f7e35cec54e47fa477958699d': ARM: rk3506_defconfig: Enable DSMC and DSMC_SLAVE configs memory: rockchip: dsmc: add dsmc local bus slave driver driver: rknpu: Update rknpu driver, version: 0.9.8 ARM: dts: rockchip: rk3506: add asrc node ASoC: rockchip: asrc: support rk3506 asrc Change-Id: Idc9acebdadc994fb1c1e44f0316d0d2ba772a319
This commit is contained in:
@@ -69,6 +69,13 @@
|
||||
clock-output-names = "xin32k";
|
||||
};
|
||||
|
||||
clk_spdifrx_to_asrc: clk-spdifrx-to-asrc {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <0>;
|
||||
clock-output-names = "clk_spdifrx_to_asrc";
|
||||
};
|
||||
|
||||
mclkin_sai0: mclkin-sai0 {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
@@ -141,6 +148,34 @@
|
||||
assigned-clocks = <&pvtpll_core>;
|
||||
assigned-clock-rates = <1200000000>;
|
||||
};
|
||||
|
||||
sai0_fs: sai0-fs {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <0>;
|
||||
clock-output-names = "sai0_fs";
|
||||
};
|
||||
|
||||
sai1_fs: sai1-fs {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <0>;
|
||||
clock-output-names = "sai1_fs";
|
||||
};
|
||||
|
||||
sai2_fs: sai2-fs {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <0>;
|
||||
clock-output-names = "sai2_fs";
|
||||
};
|
||||
|
||||
sai3_fs: sai3-fs {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <0>;
|
||||
clock-output-names = "sai3_fs";
|
||||
};
|
||||
};
|
||||
|
||||
cpus {
|
||||
@@ -909,6 +944,46 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
asrc0: asrc@ff3c0000 {
|
||||
compatible = "rockchip,rk3506-asrc";
|
||||
reg = <0xff3c0000 0x1000>;
|
||||
interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cru CLK_ASRC0>, <&cru HCLK_ASRC0>,
|
||||
<&cru LRCK_ASRC0_SRC>, <&cru LRCK_ASRC0_DST>;
|
||||
clock-names = "mclk", "hclk",
|
||||
"src_lrck", "dst_lrck";
|
||||
// dmas = <&dmac0 0 0xff2880a4 0x00010001 0xff2880a8 0x00030002>,
|
||||
// <&dmac0 1 0xff2880a4 0x00020002 0xff2880a8 0x000c0008>;
|
||||
dmas = <&dmac1 16 0xff2880a4 0x00010000 0x0 0x0>,
|
||||
<&dmac1 17 0xff2880a4 0x00020000 0x0 0x0>;
|
||||
dma-names = "rx", "tx";
|
||||
resets = <&cru SRST_ASRC0>, <&cru SRST_H_ASRC0>;
|
||||
reset-names = "m", "h";
|
||||
#sound-dai-cells = <0>;
|
||||
sound-name-prefix = "ASRC0";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
asrc1: asrc@ff3d0000 {
|
||||
compatible = "rockchip,rk3506-asrc";
|
||||
reg = <0xff3d0000 0x1000>;
|
||||
interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cru CLK_ASRC1>, <&cru HCLK_ASRC1>,
|
||||
<&cru LRCK_ASRC1_SRC>, <&cru LRCK_ASRC1_DST>;
|
||||
clock-names = "mclk", "hclk",
|
||||
"src_lrck", "dst_lrck";
|
||||
// dmas = <&dmac0 2 0xff2880a4 0x00040004 0xff2880a8 0x00300020>,
|
||||
// <&dmac0 3 0xff2880a4 0x00080008 0xff2880a8 0x00c00080>;
|
||||
dmas = <&dmac1 18 0xff2880a4 0x00040000 0x0 0x0>,
|
||||
<&dmac1 19 0xff2880a4 0x00080000 0x0 0x0>;
|
||||
dma-names = "rx", "tx";
|
||||
resets = <&cru SRST_ASRC1>, <&cru SRST_H_ASRC1>;
|
||||
reset-names = "m", "h";
|
||||
#sound-dai-cells = <0>;
|
||||
sound-name-prefix = "ASRC1";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
mmc: mmc@ff480000 {
|
||||
compatible = "rockchip,rk3506-dw-mshc", "rockchip,rk3288-dw-mshc";
|
||||
reg = <0xff480000 0x4000>;
|
||||
|
||||
@@ -306,6 +306,9 @@ CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y
|
||||
CONFIG_DEVFREQ_GOV_USERSPACE=y
|
||||
CONFIG_EXTCON=y
|
||||
CONFIG_EXTCON_USB_GPIO=y
|
||||
CONFIG_MEMORY=y
|
||||
CONFIG_ROCKCHIP_DSMC=y
|
||||
CONFIG_ROCKCHIP_DSMC_SLAVE=y
|
||||
CONFIG_IIO=y
|
||||
CONFIG_ROCKCHIP_FLEXBUS_ADC=y
|
||||
CONFIG_ROCKCHIP_SARADC=y
|
||||
|
||||
@@ -8,3 +8,9 @@ config ROCKCHIP_DSMC
|
||||
depends on ARCH_ROCKCHIP
|
||||
help
|
||||
For enable the Rockchip DSMC driver.
|
||||
|
||||
config ROCKCHIP_DSMC_SLAVE
|
||||
tristate "Rockchip Double Data Rate Serial Memory Controller(DSMC) slave driver"
|
||||
depends on ARCH_ROCKCHIP
|
||||
help
|
||||
For enable the Rockchip DSMC SLAVE driver.
|
||||
@@ -5,3 +5,5 @@
|
||||
|
||||
obj-$(CONFIG_ROCKCHIP_DSMC) += dsmc.o
|
||||
dsmc-y += dsmc-controller.o dsmc-lb-device.o dsmc-host.o
|
||||
|
||||
obj-$(CONFIG_ROCKCHIP_DSMC_SLAVE) += dsmc-lb-slave.o
|
||||
|
||||
330
drivers/memory/rockchip/dsmc-lb-slave.c
Normal file
330
drivers/memory/rockchip/dsmc-lb-slave.c
Normal file
@@ -0,0 +1,330 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2024 Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
#include <linux/clk.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#include "dsmc-host.h"
|
||||
#include "dsmc-lb-slave.h"
|
||||
|
||||
struct dsmc_soc_info {
|
||||
int (*dsmc_soc_init)(struct platform_device *pdev);
|
||||
};
|
||||
|
||||
struct dsmc_lb_slv_map {
|
||||
phys_addr_t phys;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
struct rockchip_dsmc_lb_slave {
|
||||
const struct dsmc_soc_info *soc_info;
|
||||
|
||||
struct device *dev;
|
||||
/* Hardware resources */
|
||||
void __iomem *regs;
|
||||
struct regmap *grf;
|
||||
struct clk *aclk;
|
||||
struct clk *hclk;
|
||||
struct reset_control *reset;
|
||||
struct reset_control *areset;
|
||||
struct reset_control *hreset;
|
||||
|
||||
struct dsmc_lb_slv_map lb_slv_mem;
|
||||
};
|
||||
|
||||
static int rk3506_dsmc_lb_slv_init(struct platform_device *pdev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct pinctrl *pinctrl;
|
||||
struct pinctrl_state *pinctrl_active;
|
||||
struct rockchip_dsmc_lb_slave *priv;
|
||||
|
||||
priv = platform_get_drvdata(pdev);
|
||||
|
||||
if (IS_ERR_OR_NULL(priv->grf)) {
|
||||
dev_err(dev, "Missing rockchip,grf property\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pinctrl = devm_pinctrl_get(dev);
|
||||
if (IS_ERR(pinctrl)) {
|
||||
dev_err(dev, "Failed to get pinctrl\n");
|
||||
return PTR_ERR(pinctrl);
|
||||
}
|
||||
|
||||
pinctrl_active = pinctrl_lookup_state(pinctrl, "active");
|
||||
if (IS_ERR(pinctrl_active)) {
|
||||
dev_err(dev, "Failed to lookup active pinctrl state\n");
|
||||
return PTR_ERR(pinctrl_active);
|
||||
}
|
||||
|
||||
/* enable dsmc slave and rdyn to normal mode */
|
||||
regmap_write(priv->grf, RK3506_GRF_SOC_CON(1),
|
||||
DSMC_SLAVE_ENABLE(1) | DSMC_SLAVE_RDYN_MODE(1));
|
||||
|
||||
/* The active iomux setting should be enabled after the pull-up week. */
|
||||
ret = pinctrl_select_state(pinctrl, pinctrl_active);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to select active pinctrl state\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct dsmc_soc_info rk3506_soc_info = {
|
||||
.dsmc_soc_init = rk3506_dsmc_lb_slv_init,
|
||||
};
|
||||
|
||||
static const struct of_device_id dsmc_lb_slave_of_match[] = {
|
||||
{ .compatible = "rockchip,rk3506-dsmc-lb-slave", .data = &rk3506_soc_info },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, dsmc_lb_slave_of_match);
|
||||
|
||||
static int rockchip_dsmc_platform_init(struct platform_device *pdev)
|
||||
{
|
||||
struct rockchip_dsmc_lb_slave *priv;
|
||||
struct device *dev = &pdev->dev;
|
||||
int ret = 0;
|
||||
|
||||
priv = platform_get_drvdata(pdev);
|
||||
|
||||
priv->soc_info = device_get_match_data(dev);
|
||||
if (!priv->soc_info) {
|
||||
dev_err(dev, "Error: No device match found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = priv->soc_info->dsmc_soc_init(pdev);
|
||||
if (ret) {
|
||||
dev_err(dev, "Error: Soc init fail!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dsmc_lb_slave_init(struct rockchip_dsmc_lb_slave *priv)
|
||||
{
|
||||
struct device *dev = priv->dev;
|
||||
|
||||
if (priv->lb_slv_mem.phys < AXI_ADDR_4GB_RANGE) {
|
||||
writel(priv->lb_slv_mem.phys, priv->regs + AXI_WR_ADDR_BASE);
|
||||
writel(priv->lb_slv_mem.phys, priv->regs + AXI_RD_ADDR_BASE);
|
||||
} else {
|
||||
dev_err(dev, "Error: Invalid address for slave memory!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* clear all h2s interrupt */
|
||||
writel(APP_H2S_INT_STA_MASK << APP_H2S_INT_STA_SHIFT,
|
||||
priv->regs + APP_H2S_INT_STA);
|
||||
|
||||
/* enable all h2s interrupt */
|
||||
writel(0xffffffff, priv->regs + APP_H2S_INT_STA_EN);
|
||||
writel(0xffffffff, priv->regs + APP_H2S_INT_STA_SIG_EN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dsmc_lb_slave_dma_trigger(struct rockchip_dsmc_lb_slave *priv)
|
||||
{
|
||||
int timeout = 1000;
|
||||
|
||||
/* wait interrupt register empty */
|
||||
while (timeout-- > 0) {
|
||||
if (!(readl(priv->regs + LBC_S2H_INT_STA) &
|
||||
(0x1 << S2H_INT_FOR_DMA_NUM)))
|
||||
break;
|
||||
udelay(1);
|
||||
if (timeout == 0) {
|
||||
dev_err(priv->dev, "Timeout waiting for s2h interrupt empty!\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
|
||||
/* trigger a slave to host interrupt which will start dma hardware mode copy */
|
||||
writel(0x1, priv->regs + APP_CON(S2H_INT_FOR_DMA_NUM));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t rockchip_dsmc_lb_slave_irq(int irq, void *data)
|
||||
{
|
||||
struct rockchip_dsmc_lb_slave *priv = data;
|
||||
|
||||
if (readl(priv->regs + LBC_CON(15)))
|
||||
dsmc_lb_slave_dma_trigger(priv);
|
||||
|
||||
/* clear all h2s interrupt */
|
||||
writel(APP_H2S_INT_STA_MASK << APP_H2S_INT_STA_SHIFT,
|
||||
priv->regs + APP_H2S_INT_STA);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int rk_dsmc_lb_slave_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct device_node *slv_map = NULL;
|
||||
struct rockchip_dsmc_lb_slave *priv;
|
||||
struct resource *mem;
|
||||
int irq, ret = 0;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
priv->regs = devm_ioremap_resource(dev, mem);
|
||||
if (IS_ERR(priv->regs))
|
||||
return PTR_ERR(priv->regs);
|
||||
|
||||
priv->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
|
||||
if (IS_ERR(priv->grf))
|
||||
dev_warn(dev, "Missing rockchip,grf property\n");
|
||||
|
||||
ret = rockchip_dsmc_platform_init(pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
priv->reset = devm_reset_control_get(dev, "dsmc_slv");
|
||||
if (IS_ERR(priv->reset)) {
|
||||
ret = PTR_ERR(priv->reset);
|
||||
dev_warn(dev, "failed to get dsmc slave reset: %d\n", ret);
|
||||
}
|
||||
priv->areset = devm_reset_control_get(dev, "a_dsmc_slv");
|
||||
if (IS_ERR(priv->areset)) {
|
||||
ret = PTR_ERR(priv->areset);
|
||||
dev_warn(dev, "failed to get dsmc slave areset: %d\n", ret);
|
||||
}
|
||||
priv->hreset = devm_reset_control_get(dev, "h_dsmc_slv");
|
||||
if (IS_ERR(priv->hreset)) {
|
||||
ret = PTR_ERR(priv->hreset);
|
||||
dev_warn(dev, "failed to get dsmc slave hreset: %d\n", ret);
|
||||
}
|
||||
|
||||
priv->aclk = devm_clk_get(dev, "aclk_dsmc_slv");
|
||||
if (IS_ERR(priv->aclk)) {
|
||||
dev_err(dev, "Can't get dsmc_slv aclk\n");
|
||||
return PTR_ERR(priv->aclk);
|
||||
}
|
||||
priv->hclk = devm_clk_get(dev, "hclk_dsmc_slv");
|
||||
if (IS_ERR(priv->hclk)) {
|
||||
dev_err(dev, "Can't get dsmc_slv hclk\n");
|
||||
return PTR_ERR(priv->hclk);
|
||||
}
|
||||
ret = clk_prepare_enable(priv->aclk);
|
||||
if (ret) {
|
||||
dev_err(dev, "Can't prepare enable dsmc aclk: %d\n", ret);
|
||||
goto err_dis_aclk;
|
||||
}
|
||||
ret = clk_prepare_enable(priv->hclk);
|
||||
if (ret) {
|
||||
dev_err(dev, "Can't prepare enable dsmc hclk: %d\n", ret);
|
||||
goto err_dis_hclk;
|
||||
}
|
||||
|
||||
slv_map = of_parse_phandle(np, "memory-region", 0);
|
||||
if (!slv_map) {
|
||||
ret = -EINVAL;
|
||||
dev_err(dev, "missing memory-region property\n");
|
||||
goto err_dis_hclk;
|
||||
}
|
||||
|
||||
ret = of_address_to_resource(slv_map, 0, mem);
|
||||
of_node_put(slv_map);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "memory-region missing reg property\n");
|
||||
goto err_dis_hclk;
|
||||
}
|
||||
if (resource_size(mem) <= 0) {
|
||||
ret = -EINVAL;
|
||||
dev_err(dev, "memory-region size error\n");
|
||||
goto err_dis_hclk;
|
||||
}
|
||||
|
||||
priv->lb_slv_mem.phys = mem->start;
|
||||
priv->lb_slv_mem.size = resource_size(mem);
|
||||
|
||||
priv->dev = dev;
|
||||
if (dsmc_lb_slave_init(priv)) {
|
||||
ret = -ENODEV;
|
||||
dev_err(dev, "dsmc local bus slave init fail!\n");
|
||||
goto err_dis_hclk;
|
||||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
ret = -ENODEV;
|
||||
dev_err(dev, "cannot find dsmc lb slave IRQ\n");
|
||||
goto err_dis_hclk;
|
||||
}
|
||||
ret = devm_request_irq(dev, irq, rockchip_dsmc_lb_slave_irq,
|
||||
0, dev_name(dev), priv);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "cannot request IRQ\n");
|
||||
goto err_dis_hclk;
|
||||
}
|
||||
|
||||
dev_info(dev, "rockchip dsmc local bus slave driver initialized\n");
|
||||
|
||||
return 0;
|
||||
|
||||
err_dis_hclk:
|
||||
clk_disable_unprepare(priv->hclk);
|
||||
err_dis_aclk:
|
||||
clk_disable_unprepare(priv->aclk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rk_dsmc_lb_slave_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct rockchip_dsmc_lb_slave *priv;
|
||||
|
||||
priv = platform_get_drvdata(pdev);
|
||||
|
||||
if (priv->aclk) {
|
||||
clk_disable_unprepare(priv->aclk);
|
||||
priv->aclk = NULL;
|
||||
}
|
||||
if (priv->hclk) {
|
||||
clk_disable_unprepare(priv->hclk);
|
||||
priv->hclk = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct platform_driver rk_dsmc_lb_slave_driver = {
|
||||
.probe = rk_dsmc_lb_slave_probe,
|
||||
.remove = rk_dsmc_lb_slave_remove,
|
||||
.driver = {
|
||||
.name = "dsmc_lb_slave",
|
||||
.of_match_table = dsmc_lb_slave_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(rk_dsmc_lb_slave_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Zhihuan He <huan.he@rock-chips.com>");
|
||||
MODULE_DESCRIPTION("ROCKCHIP DSMC SLAVE driver");
|
||||
@@ -67,4 +67,9 @@
|
||||
#define LBC_S2H_INT_STA_SIG_EN_SHIFT (0)
|
||||
#define LBC_S2H_INT_STA_SIG_EN_MASK (0xFFFF)
|
||||
|
||||
#define DSMC_SLAVE_ENABLE(n) ((0x1 << (4 + 16)) | ((n) << 4))
|
||||
#define DSMC_SLAVE_RDYN_MODE(n) ((0x1 << (5 + 16)) | ((n) << 5))
|
||||
|
||||
#define AXI_ADDR_4GB_RANGE (1ULL << 32)
|
||||
|
||||
#endif /* __BUS_ROCKCHIP_ROCKCHIP_DSMC_SLAVE_H */
|
||||
|
||||
@@ -29,10 +29,10 @@
|
||||
|
||||
#define DRIVER_NAME "rknpu"
|
||||
#define DRIVER_DESC "RKNPU driver"
|
||||
#define DRIVER_DATE "20240424"
|
||||
#define DRIVER_DATE "20240828"
|
||||
#define DRIVER_MAJOR 0
|
||||
#define DRIVER_MINOR 9
|
||||
#define DRIVER_PATCHLEVEL 7
|
||||
#define DRIVER_PATCHLEVEL 8
|
||||
|
||||
#define LOG_TAG "RKNPU"
|
||||
|
||||
@@ -174,6 +174,7 @@ struct rknpu_device {
|
||||
int iommu_domain_id;
|
||||
struct iommu_domain *iommu_domains[RKNPU_MAX_IOMMU_DOMAIN_NUM];
|
||||
struct sg_table *cache_sgt[RKNPU_CACHE_SG_TABLE_NUM];
|
||||
atomic_t iommu_domain_refcount;
|
||||
};
|
||||
|
||||
struct rknpu_session {
|
||||
|
||||
@@ -49,6 +49,9 @@ void rknpu_iommu_dma_unmap_sg(struct device *dev, struct scatterlist *sg,
|
||||
int rknpu_iommu_init_domain(struct rknpu_device *rknpu_dev);
|
||||
int rknpu_iommu_switch_domain(struct rknpu_device *rknpu_dev, int domain_id);
|
||||
void rknpu_iommu_free_domains(struct rknpu_device *rknpu_dev);
|
||||
int rknpu_iommu_domain_get_and_switch(struct rknpu_device *rknpu_dev,
|
||||
int domain_id);
|
||||
int rknpu_iommu_domain_put(struct rknpu_device *rknpu_dev);
|
||||
|
||||
#if KERNEL_VERSION(5, 10, 0) < LINUX_VERSION_CODE
|
||||
int iommu_get_dma_cookie(struct iommu_domain *domain);
|
||||
|
||||
@@ -485,8 +485,11 @@ static int rknpu_action(struct rknpu_device *rknpu_dev,
|
||||
ret = 0;
|
||||
break;
|
||||
case RKNPU_SET_IOMMU_DOMAIN_ID: {
|
||||
ret = rknpu_iommu_switch_domain(rknpu_dev,
|
||||
*(int32_t *)&args->value);
|
||||
ret = rknpu_iommu_domain_get_and_switch(
|
||||
rknpu_dev, *(int32_t *)&args->value);
|
||||
if (ret)
|
||||
break;
|
||||
rknpu_iommu_domain_put(rknpu_dev);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -1497,6 +1500,7 @@ static int rknpu_probe(struct platform_device *pdev)
|
||||
rknpu_power_off(rknpu_dev);
|
||||
atomic_set(&rknpu_dev->power_refcount, 0);
|
||||
atomic_set(&rknpu_dev->cmdline_power_refcount, 0);
|
||||
atomic_set(&rknpu_dev->iommu_domain_refcount, 0);
|
||||
|
||||
rknpu_debugger_init(rknpu_dev);
|
||||
rknpu_init_timer(rknpu_dev);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <drm/drm_file.h>
|
||||
#include <drm/drm_drv.h>
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/shmem_fs.h>
|
||||
#include <linux/dma-buf.h>
|
||||
#include <linux/iommu.h>
|
||||
@@ -695,8 +696,13 @@ rknpu_gem_object_create(struct drm_device *drm, unsigned int flags,
|
||||
if (IS_ERR(rknpu_obj))
|
||||
return rknpu_obj;
|
||||
|
||||
if (!rknpu_iommu_switch_domain(rknpu_dev, iommu_domain_id))
|
||||
rknpu_obj->iommu_domain_id = iommu_domain_id;
|
||||
if (rknpu_iommu_domain_get_and_switch(rknpu_dev, iommu_domain_id)) {
|
||||
LOG_DEV_ERROR(rknpu_dev->dev, "%s error\n", __func__);
|
||||
rknpu_gem_release(rknpu_obj);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
rknpu_obj->iommu_domain_id = iommu_domain_id;
|
||||
|
||||
if (!rknpu_dev->iommu_en && (flags & RKNPU_MEM_NON_CONTIGUOUS)) {
|
||||
/*
|
||||
@@ -788,6 +794,8 @@ rknpu_gem_object_create(struct drm_device *drm, unsigned int flags,
|
||||
goto gem_release;
|
||||
}
|
||||
|
||||
rknpu_iommu_domain_put(rknpu_dev);
|
||||
|
||||
LOG_DEBUG(
|
||||
"created dma addr: %pad, cookie: %p, ddr size: %lu, sram size: %lu, nbuf size: %lu, attrs: %#lx, flags: %#x, iommu domain id: %d\n",
|
||||
&rknpu_obj->dma_addr, rknpu_obj->cookie, rknpu_obj->size,
|
||||
@@ -805,6 +813,8 @@ mm_free:
|
||||
gem_release:
|
||||
rknpu_gem_release(rknpu_obj);
|
||||
|
||||
rknpu_iommu_domain_put(rknpu_dev);
|
||||
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
@@ -812,13 +822,26 @@ void rknpu_gem_object_destroy(struct rknpu_gem_object *rknpu_obj)
|
||||
{
|
||||
struct drm_gem_object *obj = &rknpu_obj->base;
|
||||
struct rknpu_device *rknpu_dev = obj->dev->dev_private;
|
||||
int wait_count = 0;
|
||||
int ret = -EINVAL;
|
||||
|
||||
LOG_DEBUG(
|
||||
"destroy dma addr: %pad, cookie: %p, size: %lu, attrs: %#lx, flags: %#x, handle count: %d\n",
|
||||
&rknpu_obj->dma_addr, rknpu_obj->cookie, rknpu_obj->size,
|
||||
rknpu_obj->dma_attrs, rknpu_obj->flags, obj->handle_count);
|
||||
|
||||
rknpu_iommu_switch_domain(rknpu_dev, rknpu_obj->iommu_domain_id);
|
||||
do {
|
||||
ret = rknpu_iommu_domain_get_and_switch(
|
||||
rknpu_dev, rknpu_obj->iommu_domain_id);
|
||||
|
||||
if (ret && ++wait_count >= 3) {
|
||||
LOG_DEV_ERROR(
|
||||
rknpu_dev->dev,
|
||||
"failed to destroy dma addr: %pad, size: %lu\n",
|
||||
&rknpu_obj->dma_addr, rknpu_obj->size);
|
||||
return;
|
||||
}
|
||||
} while (ret);
|
||||
|
||||
/*
|
||||
* do not release memory region from exporter.
|
||||
@@ -847,6 +870,7 @@ void rknpu_gem_object_destroy(struct rknpu_gem_object *rknpu_obj)
|
||||
}
|
||||
|
||||
rknpu_gem_release(rknpu_obj);
|
||||
rknpu_iommu_domain_put(rknpu_dev);
|
||||
}
|
||||
|
||||
int rknpu_gem_create_ioctl(struct drm_device *drm, void *data,
|
||||
@@ -903,16 +927,29 @@ int rknpu_gem_destroy_ioctl(struct drm_device *drm, void *data,
|
||||
struct rknpu_device *rknpu_dev = drm->dev_private;
|
||||
struct rknpu_gem_object *rknpu_obj = NULL;
|
||||
struct rknpu_mem_destroy *args = data;
|
||||
int ret = 0;
|
||||
int wait_count = 0;
|
||||
|
||||
rknpu_obj = rknpu_gem_object_find(file_priv, args->handle);
|
||||
if (!rknpu_obj)
|
||||
return -EINVAL;
|
||||
|
||||
rknpu_iommu_switch_domain(rknpu_dev, rknpu_obj->iommu_domain_id);
|
||||
do {
|
||||
ret = rknpu_iommu_domain_get_and_switch(
|
||||
rknpu_dev, rknpu_obj->iommu_domain_id);
|
||||
|
||||
// rknpu_gem_object_put(&rknpu_obj->base);
|
||||
if (ret && ++wait_count >= 3) {
|
||||
LOG_DEV_ERROR(rknpu_dev->dev,
|
||||
"failed to destroy memory\n");
|
||||
return ret;
|
||||
}
|
||||
} while (ret);
|
||||
|
||||
return rknpu_gem_handle_destroy(file_priv, args->handle);
|
||||
ret = rknpu_gem_handle_destroy(file_priv, args->handle);
|
||||
|
||||
rknpu_iommu_domain_put(rknpu_dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if RKNPU_GEM_ALLOC_FROM_PAGES
|
||||
@@ -1647,6 +1684,12 @@ int rknpu_gem_sync_ioctl(struct drm_device *dev, void *data,
|
||||
if (!(rknpu_obj->flags & RKNPU_MEM_CACHEABLE))
|
||||
return -EINVAL;
|
||||
|
||||
if (rknpu_iommu_domain_get_and_switch(rknpu_dev,
|
||||
rknpu_obj->iommu_domain_id)) {
|
||||
LOG_DEV_ERROR(rknpu_dev->dev, "%s error\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!(rknpu_obj->flags & RKNPU_MEM_NON_CONTIGUOUS)) {
|
||||
if (args->flags & RKNPU_MEM_SYNC_TO_DEVICE) {
|
||||
dma_sync_single_range_for_device(
|
||||
@@ -1708,5 +1751,7 @@ int rknpu_gem_sync_ioctl(struct drm_device *dev, void *data,
|
||||
}
|
||||
}
|
||||
|
||||
rknpu_iommu_domain_put(rknpu_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -5,9 +5,13 @@
|
||||
*/
|
||||
|
||||
#include <linux/dma-map-ops.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/jiffies.h>
|
||||
|
||||
#include "rknpu_iommu.h"
|
||||
|
||||
#define RKNPU_SWITCH_DOMAIN_WAIT_TIME_MS 6000
|
||||
|
||||
dma_addr_t rknpu_iommu_dma_alloc_iova(struct iommu_domain *domain, size_t size,
|
||||
u64 dma_limit, struct device *dev,
|
||||
bool size_aligned)
|
||||
@@ -434,11 +438,8 @@ int rknpu_iommu_switch_domain(struct rknpu_device *rknpu_dev, int domain_id)
|
||||
if (!bus)
|
||||
return -EFAULT;
|
||||
|
||||
mutex_lock(&rknpu_dev->domain_lock);
|
||||
|
||||
src_domain_id = rknpu_dev->iommu_domain_id;
|
||||
if (domain_id == src_domain_id) {
|
||||
mutex_unlock(&rknpu_dev->domain_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -447,7 +448,6 @@ int rknpu_iommu_switch_domain(struct rknpu_device *rknpu_dev, int domain_id)
|
||||
LOG_DEV_ERROR(
|
||||
rknpu_dev->dev,
|
||||
"mismatch domain get from iommu_get_domain_for_dev\n");
|
||||
mutex_unlock(&rknpu_dev->domain_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -466,7 +466,6 @@ int rknpu_iommu_switch_domain(struct rknpu_device *rknpu_dev, int domain_id)
|
||||
"failed to reattach src iommu domain, id: %d\n",
|
||||
src_domain_id);
|
||||
}
|
||||
mutex_unlock(&rknpu_dev->domain_lock);
|
||||
return ret;
|
||||
}
|
||||
rknpu_dev->iommu_domain_id = domain_id;
|
||||
@@ -477,7 +476,6 @@ int rknpu_iommu_switch_domain(struct rknpu_device *rknpu_dev, int domain_id)
|
||||
if (!dst_domain) {
|
||||
LOG_DEV_ERROR(rknpu_dev->dev,
|
||||
"failed to allocate iommu domain\n");
|
||||
mutex_unlock(&rknpu_dev->domain_lock);
|
||||
return -EIO;
|
||||
}
|
||||
// init domain iova_cookie
|
||||
@@ -491,7 +489,6 @@ int rknpu_iommu_switch_domain(struct rknpu_device *rknpu_dev, int domain_id)
|
||||
"failed to attach iommu domain, id: %d, ret: %d\n",
|
||||
domain_id, ret);
|
||||
iommu_domain_free(dst_domain);
|
||||
mutex_unlock(&rknpu_dev->domain_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -508,19 +505,74 @@ int rknpu_iommu_switch_domain(struct rknpu_device *rknpu_dev, int domain_id)
|
||||
// reset default iommu domain
|
||||
rknpu_dev->iommu_group->default_domain = dst_domain;
|
||||
|
||||
mutex_unlock(&rknpu_dev->domain_lock);
|
||||
|
||||
LOG_INFO("switch iommu domain from %d to %d\n", src_domain_id,
|
||||
domain_id);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rknpu_iommu_domain_get_and_switch(struct rknpu_device *rknpu_dev,
|
||||
int domain_id)
|
||||
{
|
||||
unsigned long timeout_jiffies =
|
||||
msecs_to_jiffies(RKNPU_SWITCH_DOMAIN_WAIT_TIME_MS);
|
||||
unsigned long start = jiffies;
|
||||
int ret = -EINVAL;
|
||||
|
||||
while (true) {
|
||||
mutex_lock(&rknpu_dev->domain_lock);
|
||||
|
||||
if (domain_id == rknpu_dev->iommu_domain_id) {
|
||||
atomic_inc(&rknpu_dev->iommu_domain_refcount);
|
||||
mutex_unlock(&rknpu_dev->domain_lock);
|
||||
break;
|
||||
}
|
||||
|
||||
if (atomic_read(&rknpu_dev->iommu_domain_refcount) == 0) {
|
||||
ret = rknpu_iommu_switch_domain(rknpu_dev, domain_id);
|
||||
if (ret) {
|
||||
LOG_DEV_ERROR(
|
||||
rknpu_dev->dev,
|
||||
"failed to switch iommu domain, id: %d, ret: %d\n",
|
||||
domain_id, ret);
|
||||
mutex_unlock(&rknpu_dev->domain_lock);
|
||||
return ret;
|
||||
}
|
||||
atomic_inc(&rknpu_dev->iommu_domain_refcount);
|
||||
mutex_unlock(&rknpu_dev->domain_lock);
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&rknpu_dev->domain_lock);
|
||||
|
||||
usleep_range(10, 100);
|
||||
if (time_after(jiffies, start + timeout_jiffies)) {
|
||||
LOG_DEV_ERROR(
|
||||
rknpu_dev->dev,
|
||||
"switch iommu domain time out, failed to switch iommu domain, id: %d\n",
|
||||
domain_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rknpu_iommu_domain_put(struct rknpu_device *rknpu_dev)
|
||||
{
|
||||
atomic_dec(&rknpu_dev->iommu_domain_refcount);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rknpu_iommu_free_domains(struct rknpu_device *rknpu_dev)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
rknpu_iommu_switch_domain(rknpu_dev, 0);
|
||||
if (rknpu_iommu_domain_get_and_switch(rknpu_dev, 0)) {
|
||||
LOG_DEV_ERROR(rknpu_dev->dev, "%s error\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 1; i < RKNPU_MAX_IOMMU_DOMAIN_NUM; i++) {
|
||||
struct iommu_domain *domain = rknpu_dev->iommu_domains[i];
|
||||
@@ -533,6 +585,8 @@ void rknpu_iommu_free_domains(struct rknpu_device *rknpu_dev)
|
||||
|
||||
rknpu_dev->iommu_domains[i] = NULL;
|
||||
}
|
||||
|
||||
rknpu_iommu_domain_put(rknpu_dev);
|
||||
}
|
||||
|
||||
#else
|
||||
@@ -547,6 +601,17 @@ int rknpu_iommu_switch_domain(struct rknpu_device *rknpu_dev, int domain_id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rknpu_iommu_domain_get_and_switch(struct rknpu_device *rknpu_dev,
|
||||
int domain_id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rknpu_iommu_domain_put(struct rknpu_device *rknpu_dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rknpu_iommu_free_domains(struct rknpu_device *rknpu_dev)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -210,8 +210,9 @@ static inline int rknpu_job_wait(struct rknpu_job *job)
|
||||
(elapse_time_us < args->timeout * 1000);
|
||||
spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags);
|
||||
LOG_ERROR(
|
||||
"job: %p, iommu domain id: %d, wait_count: %d, continue wait: %d, commit elapse time: %lldus, wait time: %lldus, timeout: %uus\n",
|
||||
job, job->iommu_domain_id, wait_count,
|
||||
"job: %p, mask: %#x, job iommu domain id: %d, dev iommu domain id: %d, wait_count: %d, continue wait: %d, commit elapse time: %lldus, wait time: %lldus, timeout: %uus\n",
|
||||
job, args->core_mask, job->iommu_domain_id,
|
||||
rknpu_dev->iommu_domain_id, wait_count,
|
||||
continue_wait,
|
||||
(job->hw_commit_time == 0 ? 0 : elapse_time_us),
|
||||
ktime_us_delta(ktime_get(), job->timestamp),
|
||||
@@ -452,9 +453,8 @@ static void rknpu_job_next(struct rknpu_device *rknpu_dev, int core_index)
|
||||
job->hw_recoder_time = job->hw_commit_time;
|
||||
spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags);
|
||||
|
||||
if (atomic_dec_and_test(&job->run_count)) {
|
||||
if (atomic_dec_and_test(&job->run_count))
|
||||
rknpu_job_commit(job);
|
||||
}
|
||||
}
|
||||
|
||||
static void rknpu_job_done(struct rknpu_job *job, int ret, int core_index)
|
||||
@@ -485,6 +485,8 @@ static void rknpu_job_done(struct rknpu_job *job, int ret, int core_index)
|
||||
if (atomic_dec_and_test(&job->interrupt_count)) {
|
||||
int use_core_num = job->use_core_num;
|
||||
|
||||
rknpu_iommu_domain_put(rknpu_dev);
|
||||
|
||||
job->flags |= RKNPU_JOB_DONE;
|
||||
job->ret = ret;
|
||||
|
||||
@@ -535,6 +537,11 @@ static void rknpu_job_schedule(struct rknpu_job *job)
|
||||
atomic_set(&job->interrupt_count, job->use_core_num);
|
||||
}
|
||||
|
||||
if (rknpu_iommu_domain_get_and_switch(rknpu_dev, job->iommu_domain_id)) {
|
||||
job->ret = -EINVAL;
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&rknpu_dev->irq_lock, flags);
|
||||
for (i = 0; i < rknpu_dev->config->num_irqs; i++) {
|
||||
if (job->args->core_mask & rknpu_core_mask(i)) {
|
||||
@@ -558,6 +565,8 @@ static void rknpu_job_abort(struct rknpu_job *job)
|
||||
unsigned long flags;
|
||||
int i = 0;
|
||||
|
||||
rknpu_iommu_domain_put(rknpu_dev);
|
||||
|
||||
msleep(100);
|
||||
|
||||
spin_lock_irqsave(&rknpu_dev->irq_lock, flags);
|
||||
@@ -843,8 +852,6 @@ int rknpu_submit_ioctl(struct drm_device *dev, void *data,
|
||||
struct rknpu_device *rknpu_dev = dev_get_drvdata(dev->dev);
|
||||
struct rknpu_submit *args = data;
|
||||
|
||||
rknpu_iommu_switch_domain(rknpu_dev, args->iommu_domain_id);
|
||||
|
||||
return rknpu_submit(rknpu_dev, args);
|
||||
}
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user