mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 10:58:48 +09:00
PCI: rockchip: Support PCIe dma transfer on RK3399 platform
Change-Id: I8545ddb459b8275489fa9b7a70e54c6b57cc514c Signed-off-by: Simon Xue <xxm@rock-chips.com>
This commit is contained in:
@@ -38,6 +38,8 @@
|
||||
#include <linux/reset.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "rockchip-pcie-dma.h"
|
||||
|
||||
/*
|
||||
* The upper 16 bits of PCIE_CLIENT_CONFIG are a write mask for the lower 16
|
||||
* bits. This allows atomic updates of the register without locking.
|
||||
@@ -101,6 +103,7 @@
|
||||
#define PCIE_CH0_ERR_ENABLE BIT(8)
|
||||
#define PCIE_CH1_ERR_ENABLE BIT(9)
|
||||
|
||||
#define PCIE_UDMA_INT_REG 0xa0
|
||||
#define PCIE_UDMA_INT_ENABLE_REG 0xa4
|
||||
|
||||
#define PCIE_UDMA_INT_ENABLE_MASK \
|
||||
@@ -186,6 +189,7 @@
|
||||
#define IB_ROOT_PORT_REG_SIZE_SHIFT 3
|
||||
#define AXI_WRAPPER_IO_WRITE 0x6
|
||||
#define AXI_WRAPPER_MEM_WRITE 0x2
|
||||
#define AXI_WRAPPER_CFG0 0xa
|
||||
#define AXI_WRAPPER_NOR_MSG 0xc
|
||||
|
||||
#define MAX_AXI_IB_ROOTPORT_REGION_NUM 3
|
||||
@@ -242,6 +246,10 @@ struct rockchip_pcie {
|
||||
u32 mem_size;
|
||||
phys_addr_t msg_bus_addr;
|
||||
phys_addr_t mem_bus_addr;
|
||||
phys_addr_t mem_reserve_start;
|
||||
size_t mem_reserve_size;
|
||||
int dma_trx_enabled;
|
||||
struct dma_trx_obj *dma_obj;
|
||||
};
|
||||
|
||||
static u32 rockchip_pcie_read(struct rockchip_pcie *rockchip, u32 reg)
|
||||
@@ -255,6 +263,21 @@ static void rockchip_pcie_write(struct rockchip_pcie *rockchip, u32 val,
|
||||
writel(val, rockchip->apb_base + reg);
|
||||
}
|
||||
|
||||
void rk_pcie_start_dma_3399(struct dma_trx_obj *obj)
|
||||
{
|
||||
struct rockchip_pcie *rockchip = dev_get_drvdata(obj->dev);
|
||||
struct dma_table *tbl = obj->cur;
|
||||
int chn = tbl->chn;
|
||||
|
||||
rockchip_pcie_write(rockchip, (u32)(tbl->phys_descs & 0xffffffff),
|
||||
PCIE_APB_CORE_UDMA_BASE + 0x14 * chn + 0x04);
|
||||
rockchip_pcie_write(rockchip, (u32)(tbl->phys_descs >> 32),
|
||||
PCIE_APB_CORE_UDMA_BASE + 0x14 * chn + 0x08);
|
||||
rockchip_pcie_write(rockchip, BIT(0) | (tbl->dir << 1),
|
||||
PCIE_APB_CORE_UDMA_BASE + 0x14 * chn + 0x00);
|
||||
}
|
||||
EXPORT_SYMBOL(rk_pcie_start_dma_3399);
|
||||
|
||||
static void rockchip_pcie_enable_bw_int(struct rockchip_pcie *rockchip)
|
||||
{
|
||||
u32 status;
|
||||
@@ -679,6 +702,31 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
rk_pcie_handle_dma_interrupt(struct rockchip_pcie *rockchip)
|
||||
{
|
||||
u32 dma_status;
|
||||
struct dma_trx_obj *obj = rockchip->dma_obj;
|
||||
|
||||
dma_status = rockchip_pcie_read(rockchip,
|
||||
PCIE_APB_CORE_UDMA_BASE + PCIE_UDMA_INT_REG);
|
||||
|
||||
/* Core: clear dma interrupt */
|
||||
rockchip_pcie_write(rockchip, dma_status,
|
||||
PCIE_APB_CORE_UDMA_BASE + PCIE_UDMA_INT_REG);
|
||||
|
||||
WARN_ONCE(!(dma_status & 0x3), "dma_status 0x%x\n", dma_status);
|
||||
|
||||
if (dma_status & (1 << 0))
|
||||
obj->dma_free = true;
|
||||
|
||||
if (list_empty(&obj->tbl_list)) {
|
||||
if (obj->dma_free &&
|
||||
obj->loop_count >= obj->loop_count_threshold)
|
||||
complete(&obj->done);
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t rockchip_pcie_subsys_irq_handler(int irq, void *arg)
|
||||
{
|
||||
struct rockchip_pcie *rockchip = arg;
|
||||
@@ -741,6 +789,7 @@ static irqreturn_t rockchip_pcie_subsys_irq_handler(int irq, void *arg)
|
||||
}
|
||||
|
||||
if (reg & PCIE_CLIENT_INT_UDMA) {
|
||||
rk_pcie_handle_dma_interrupt(rockchip);
|
||||
rockchip_pcie_write(rockchip, sub_reg, PCIE_CLIENT_INT_STATUS);
|
||||
rockchip_pcie_write(rockchip, reg, PCIE_CLIENT_INT_STATUS);
|
||||
}
|
||||
@@ -833,6 +882,8 @@ static int rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip)
|
||||
struct device *dev = rockchip->dev;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct device_node *node = dev->of_node;
|
||||
struct device_node *mem;
|
||||
struct resource reg;
|
||||
struct resource *regs;
|
||||
int irq;
|
||||
int err;
|
||||
@@ -1007,6 +1058,28 @@ static int rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip)
|
||||
dev_info(dev, "no vpcie0v9 regulator found\n");
|
||||
}
|
||||
|
||||
mem = of_parse_phandle(node, "memory-region", 0);
|
||||
if (!mem) {
|
||||
dev_warn(dev, "missing \"memory-region\" property\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = of_address_to_resource(mem, 0, ®);
|
||||
if (err < 0) {
|
||||
dev_warn(dev, "missing \"reg\" property\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
rockchip->mem_reserve_start = reg.start;
|
||||
rockchip->mem_reserve_size = resource_size(®);
|
||||
|
||||
err = of_property_read_u32(node, "dma_trx_enabled",
|
||||
&rockchip->dma_trx_enabled);
|
||||
if (err < 0) {
|
||||
dev_warn(dev, "missing \"dma_trx_enabled\" property\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1185,6 +1258,13 @@ static int rockchip_cfg_atu(struct rockchip_pcie *rockchip)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
/* Workaround for PCIe DMA transfer */
|
||||
if (rockchip->dma_trx_enabled) {
|
||||
rockchip_pcie_prog_ob_atu(rockchip, 0, AXI_WRAPPER_CFG0, 12,
|
||||
0x0, 0x0);
|
||||
rockchip_pcie_prog_ob_atu(rockchip, 1, AXI_WRAPPER_MEM_WRITE,
|
||||
32 - 1, rockchip->mem_reserve_start, 0x0);
|
||||
}
|
||||
|
||||
err = rockchip_pcie_prog_ib_atu(rockchip, 2, 32 - 1, 0x0, 0);
|
||||
if (err) {
|
||||
@@ -1417,6 +1497,14 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
|
||||
pcie_bus_configure_settings(child);
|
||||
|
||||
pci_bus_add_devices(bus);
|
||||
|
||||
rockchip->dma_obj = rk_pcie_dma_obj_probe(dev);
|
||||
if (IS_ERR(rockchip->dma_obj)) {
|
||||
dev_err(dev, "failed to prepare dma object\n");
|
||||
err = -EINVAL;
|
||||
goto err_free_res;
|
||||
}
|
||||
|
||||
return err;
|
||||
|
||||
err_free_res:
|
||||
|
||||
Reference in New Issue
Block a user