mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
PCI: rockchip: update rk3399 host driver
1. Delete unused files 2. Add PCIe udma transfer support 3. Use default Max Payload size setting(128 Bytes) It's safe to use default Max Payload size setting to support most devices Change-Id: I68b60192a90962e03fe52b907a17234e8567e4b4 Signed-off-by: Simon Xue <xxm@rock-chips.com>
This commit is contained in:
@@ -218,6 +218,13 @@ config PCIE_ROCKCHIP_HOST
|
||||
There is 1 internal PCIe port available to support GEN2 with
|
||||
4 slots.
|
||||
|
||||
config ROCKCHIP_PCIE_DMA_OBJ
|
||||
bool "Rockchip PCIe uDMA transfer support"
|
||||
depends on PCIE_ROCKCHIP_HOST
|
||||
default n
|
||||
help
|
||||
Say y to enable p2p DMA transfer between PCIe components.
|
||||
|
||||
config PCIE_ROCKCHIP_EP
|
||||
bool "Rockchip PCIe endpoint controller"
|
||||
depends on ARCH_ROCKCHIP || COMPILE_TEST
|
||||
|
||||
@@ -25,6 +25,7 @@ obj-$(CONFIG_PCIE_ALTERA_MSI) += pcie-altera-msi.o
|
||||
obj-$(CONFIG_PCIE_ROCKCHIP) += pcie-rockchip.o
|
||||
obj-$(CONFIG_PCIE_ROCKCHIP_EP) += pcie-rockchip-ep.o
|
||||
obj-$(CONFIG_PCIE_ROCKCHIP_HOST) += pcie-rockchip-host.o
|
||||
obj-$(CONFIG_ROCKCHIP_PCIE_DMA_OBJ) += rockchip-pcie-dma.o
|
||||
obj-$(CONFIG_PCIE_MEDIATEK) += pcie-mediatek.o
|
||||
obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o
|
||||
obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o
|
||||
|
||||
@@ -38,6 +38,22 @@
|
||||
|
||||
#include "../pci.h"
|
||||
#include "pcie-rockchip.h"
|
||||
#include "rockchip-pcie-dma.h"
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -302,6 +318,7 @@ static int rockchip_pcie_host_init_port(struct rockchip_pcie *rockchip)
|
||||
struct device *dev = rockchip->dev;
|
||||
int err, i = MAX_LANE_NUM;
|
||||
u32 status;
|
||||
int timeouts = 500;
|
||||
|
||||
gpiod_set_value_cansleep(rockchip->ep_gpio, 0);
|
||||
|
||||
@@ -333,15 +350,26 @@ static int rockchip_pcie_host_init_port(struct rockchip_pcie *rockchip)
|
||||
|
||||
gpiod_set_value_cansleep(rockchip->ep_gpio, 1);
|
||||
|
||||
if (rockchip->wait_ep)
|
||||
timeouts = 10000;
|
||||
|
||||
/* 500ms timeout value should be enough for Gen1/2 training */
|
||||
err = readl_poll_timeout(rockchip->apb_base + PCIE_CLIENT_BASIC_STATUS1,
|
||||
status, PCIE_LINK_UP(status), 20,
|
||||
500 * USEC_PER_MSEC);
|
||||
timeouts * USEC_PER_MSEC);
|
||||
if (err) {
|
||||
dev_err(dev, "PCIe link training gen1 timeout!\n");
|
||||
goto err_power_off_phy;
|
||||
}
|
||||
|
||||
err = readl_poll_timeout(rockchip->apb_base + PCIE_CLIENT_DEBUG_OUT_0,
|
||||
status, PCIE_LINK_IS_L0(status), 20,
|
||||
timeouts * USEC_PER_MSEC);
|
||||
if (err) {
|
||||
dev_err(dev, "LTSSM is not L0!\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (rockchip->link_gen == 2) {
|
||||
/*
|
||||
* Enable retrain for gen2. This should be configured only after
|
||||
@@ -391,11 +419,6 @@ static int rockchip_pcie_host_init_port(struct rockchip_pcie *rockchip)
|
||||
rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_LINK_CAP);
|
||||
}
|
||||
|
||||
status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_DCSR);
|
||||
status &= ~PCIE_RC_CONFIG_DCSR_MPS_MASK;
|
||||
status |= PCIE_RC_CONFIG_DCSR_MPS_256;
|
||||
rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_DCSR);
|
||||
|
||||
return 0;
|
||||
err_power_off_phy:
|
||||
while (i--)
|
||||
@@ -406,6 +429,33 @@ err_power_off_phy:
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline void
|
||||
rockchip_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->irq_num++;
|
||||
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;
|
||||
@@ -414,9 +464,10 @@ static irqreturn_t rockchip_pcie_subsys_irq_handler(int irq, void *arg)
|
||||
u32 sub_reg;
|
||||
|
||||
reg = rockchip_pcie_read(rockchip, PCIE_CLIENT_INT_STATUS);
|
||||
sub_reg = rockchip_pcie_read(rockchip, PCIE_CORE_INT_STATUS);
|
||||
dev_dbg(dev, "reg = 0x%x, sub_reg = 0x%x\n", reg, sub_reg);
|
||||
if (reg & PCIE_CLIENT_INT_LOCAL) {
|
||||
dev_dbg(dev, "local interrupt received\n");
|
||||
sub_reg = rockchip_pcie_read(rockchip, PCIE_CORE_INT_STATUS);
|
||||
if (sub_reg & PCIE_CORE_INT_PRFPE)
|
||||
dev_dbg(dev, "parity error detected while reading from the PNP receive FIFO RAM\n");
|
||||
|
||||
@@ -466,6 +517,12 @@ static irqreturn_t rockchip_pcie_subsys_irq_handler(int irq, void *arg)
|
||||
rockchip_pcie_clr_bw_int(rockchip);
|
||||
}
|
||||
|
||||
if (reg & PCIE_CLIENT_INT_UDMA) {
|
||||
rockchip_pcie_handle_dma_interrupt(rockchip);
|
||||
rockchip_pcie_write(rockchip, sub_reg, PCIE_CLIENT_INT_STATUS);
|
||||
rockchip_pcie_write(rockchip, reg, PCIE_CLIENT_INT_STATUS);
|
||||
}
|
||||
|
||||
rockchip_pcie_write(rockchip, reg & PCIE_CLIENT_INT_LOCAL,
|
||||
PCIE_CLIENT_INT_STATUS);
|
||||
|
||||
@@ -697,6 +754,8 @@ static void rockchip_pcie_enable_interrupts(struct rockchip_pcie *rockchip)
|
||||
PCIE_CORE_INT_MASK);
|
||||
|
||||
rockchip_pcie_enable_bw_int(rockchip);
|
||||
rockchip_pcie_write(rockchip, PCIE_UDMA_INT_ENABLE_MASK,
|
||||
PCIE_APB_CORE_UDMA_BASE + PCIE_UDMA_INT_ENABLE_REG);
|
||||
}
|
||||
|
||||
static int rockchip_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
|
||||
@@ -825,6 +884,12 @@ static int rockchip_pcie_cfg_atu(struct rockchip_pcie *rockchip)
|
||||
}
|
||||
}
|
||||
|
||||
/* Workaround for PCIe DMA transfer */
|
||||
if (rockchip->dma_trx_enabled) {
|
||||
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) {
|
||||
dev_err(dev, "program RC mem inbound ATU failed\n");
|
||||
@@ -853,6 +918,11 @@ static int rockchip_pcie_cfg_atu(struct rockchip_pcie *rockchip)
|
||||
|
||||
rockchip->msg_bus_addr = rockchip->mem_bus_addr +
|
||||
((reg_no + offset) << 20);
|
||||
|
||||
rockchip->msg_region = devm_ioremap(dev, rockchip->msg_bus_addr, SZ_1M);
|
||||
if (!rockchip->msg_region)
|
||||
err = -ENOMEM;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -861,6 +931,10 @@ static int rockchip_pcie_wait_l2(struct rockchip_pcie *rockchip)
|
||||
u32 value;
|
||||
int err;
|
||||
|
||||
/* Don't enter L2 state when no ep connected */
|
||||
if (rockchip->dma_trx_enabled == 1)
|
||||
return 0;
|
||||
|
||||
/* send PME_TURN_OFF message */
|
||||
writel(0x0, rockchip->msg_region + PCIE_RC_SEND_PME_OFF);
|
||||
|
||||
@@ -876,11 +950,15 @@ static int rockchip_pcie_wait_l2(struct rockchip_pcie *rockchip)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused rockchip_pcie_suspend_noirq(struct device *dev)
|
||||
static int rockchip_pcie_suspend_for_user(struct device *dev)
|
||||
{
|
||||
struct rockchip_pcie *rockchip = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
/* disable ltssm */
|
||||
rockchip_pcie_write(rockchip, PCIE_CLIENT_LINK_TRAIN_DISABLE,
|
||||
PCIE_CLIENT_CONFIG);
|
||||
|
||||
/* disable core and cli int since we don't need to ack PME_ACK */
|
||||
rockchip_pcie_write(rockchip, (PCIE_CLIENT_INT_CLI << 16) |
|
||||
PCIE_CLIENT_INT_CLI, PCIE_CLIENT_INT_MASK);
|
||||
@@ -894,6 +972,37 @@ static int __maybe_unused rockchip_pcie_suspend_noirq(struct device *dev)
|
||||
|
||||
rockchip_pcie_deinit_phys(rockchip);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rockchip_pcie_resume_for_user(struct device *dev)
|
||||
{
|
||||
struct rockchip_pcie *rockchip = dev_get_drvdata(dev);
|
||||
int err;
|
||||
|
||||
err = rockchip_pcie_host_init_port(rockchip);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = rockchip_pcie_cfg_atu(rockchip);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Need this to enter L1 again */
|
||||
rockchip_pcie_update_txcredit_mui(rockchip);
|
||||
rockchip_pcie_enable_interrupts(rockchip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused rockchip_pcie_suspend_noirq(struct device *dev)
|
||||
{
|
||||
struct rockchip_pcie *rockchip = dev_get_drvdata(dev);
|
||||
int ret = 0;
|
||||
|
||||
if (!rockchip->dma_trx_enabled)
|
||||
ret = rockchip_pcie_suspend_for_user(dev);
|
||||
|
||||
rockchip_pcie_disable_clocks(rockchip);
|
||||
|
||||
if (!IS_ERR(rockchip->vpcie0v9))
|
||||
@@ -919,44 +1028,130 @@ static int __maybe_unused rockchip_pcie_resume_noirq(struct device *dev)
|
||||
if (err)
|
||||
goto err_disable_0v9;
|
||||
|
||||
err = rockchip_pcie_host_init_port(rockchip);
|
||||
if (err)
|
||||
goto err_pcie_resume;
|
||||
if (!rockchip->dma_trx_enabled)
|
||||
err = rockchip_pcie_resume_for_user(dev);
|
||||
|
||||
err = rockchip_pcie_cfg_atu(rockchip);
|
||||
if (err)
|
||||
goto err_err_deinit_port;
|
||||
return err;
|
||||
|
||||
/* Need this to enter L1 again */
|
||||
rockchip_pcie_update_txcredit_mui(rockchip);
|
||||
rockchip_pcie_enable_interrupts(rockchip);
|
||||
|
||||
return 0;
|
||||
|
||||
err_err_deinit_port:
|
||||
rockchip_pcie_deinit_phys(rockchip);
|
||||
err_pcie_resume:
|
||||
rockchip_pcie_disable_clocks(rockchip);
|
||||
err_disable_0v9:
|
||||
if (!IS_ERR(rockchip->vpcie0v9))
|
||||
regulator_disable(rockchip->vpcie0v9);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int rockchip_pcie_really_probe(struct rockchip_pcie *rockchip)
|
||||
{
|
||||
int err;
|
||||
struct pci_bus *bus, *child;
|
||||
struct device *dev = rockchip->dev;
|
||||
|
||||
err = rockchip_pcie_host_init_port(rockchip);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
rockchip_pcie_enable_interrupts(rockchip);
|
||||
|
||||
err = rockchip_pcie_cfg_atu(rockchip);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
list_splice_init(&rockchip->resources, &rockchip->bridge->windows);
|
||||
rockchip->bridge->dev.parent = dev;
|
||||
rockchip->bridge->sysdata = rockchip;
|
||||
rockchip->bridge->busnr = 0;
|
||||
rockchip->bridge->ops = &rockchip_pcie_ops;
|
||||
rockchip->bridge->map_irq = of_irq_parse_and_map_pci;
|
||||
rockchip->bridge->swizzle_irq = pci_common_swizzle;
|
||||
|
||||
err = pci_scan_root_bus_bridge(rockchip->bridge);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
bus = rockchip->bridge->bus;
|
||||
|
||||
rockchip->root_bus = bus;
|
||||
|
||||
pci_bus_size_bridges(bus);
|
||||
pci_bus_assign_resources(bus);
|
||||
list_for_each_entry(child, &bus->children, node)
|
||||
pcie_bus_configure_settings(child);
|
||||
|
||||
pci_bus_add_devices(bus);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t pcie_deferred_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
u32 val = 0;
|
||||
int err;
|
||||
struct rockchip_pcie *rockchip = dev_get_drvdata(dev);
|
||||
|
||||
err = kstrtou32(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (val) {
|
||||
rockchip->wait_ep = 1;
|
||||
err = rockchip_pcie_really_probe(rockchip);
|
||||
if (err)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t pcie_reset_ep_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
u32 val = 0;
|
||||
int err;
|
||||
struct rockchip_pcie *rockchip = dev_get_drvdata(dev);
|
||||
struct dma_trx_obj *obj = rockchip->dma_obj;
|
||||
|
||||
dev_info(dev, "loop_cout = %d\n", obj->loop_count);
|
||||
|
||||
err = kstrtou32(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (val == PCIE_USER_UNLINK)
|
||||
rockchip_pcie_suspend_for_user(rockchip->dev);
|
||||
else if (val == PCIE_USER_RELINK)
|
||||
rockchip_pcie_resume_for_user(rockchip->dev);
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_WO(pcie_deferred);
|
||||
static DEVICE_ATTR_WO(pcie_reset_ep);
|
||||
|
||||
static struct attribute *pcie_attrs[] = {
|
||||
&dev_attr_pcie_deferred.attr,
|
||||
&dev_attr_pcie_reset_ep.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group pcie_attr_group = {
|
||||
.attrs = pcie_attrs,
|
||||
};
|
||||
|
||||
static int rockchip_pcie_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rockchip_pcie *rockchip;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct pci_bus *bus, *child;
|
||||
struct pci_host_bridge *bridge;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource_entry *win;
|
||||
resource_size_t io_base;
|
||||
struct resource *mem;
|
||||
struct resource *io;
|
||||
int err;
|
||||
|
||||
LIST_HEAD(res);
|
||||
|
||||
if (!dev->of_node)
|
||||
return -ENODEV;
|
||||
|
||||
@@ -966,6 +1161,8 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
|
||||
|
||||
rockchip = pci_host_bridge_priv(bridge);
|
||||
|
||||
rockchip->bridge = bridge;
|
||||
|
||||
platform_set_drvdata(pdev, rockchip);
|
||||
rockchip->dev = dev;
|
||||
rockchip->is_rc = true;
|
||||
@@ -984,27 +1181,23 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
|
||||
goto err_set_vpcie;
|
||||
}
|
||||
|
||||
err = rockchip_pcie_host_init_port(rockchip);
|
||||
if (err)
|
||||
goto err_vpcie;
|
||||
|
||||
rockchip_pcie_enable_interrupts(rockchip);
|
||||
|
||||
err = rockchip_pcie_init_irq_domain(rockchip);
|
||||
if (err < 0)
|
||||
goto err_deinit_port;
|
||||
goto err_vpcie;
|
||||
|
||||
INIT_LIST_HEAD(&rockchip->resources);
|
||||
|
||||
err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,
|
||||
&res, &io_base);
|
||||
&rockchip->resources, &io_base);
|
||||
if (err)
|
||||
goto err_remove_irq_domain;
|
||||
|
||||
err = devm_request_pci_bus_resources(dev, &res);
|
||||
err = devm_request_pci_bus_resources(dev, &rockchip->resources);
|
||||
if (err)
|
||||
goto err_free_res;
|
||||
|
||||
/* Get the I/O and memory ranges from DT */
|
||||
resource_list_for_each_entry(win, &res) {
|
||||
resource_list_for_each_entry(win, &rockchip->resources) {
|
||||
switch (resource_type(win->res)) {
|
||||
case IORESOURCE_IO:
|
||||
io = win->res;
|
||||
@@ -1033,48 +1226,41 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
|
||||
}
|
||||
}
|
||||
|
||||
err = rockchip_pcie_cfg_atu(rockchip);
|
||||
if (err)
|
||||
goto err_unmap_iospace;
|
||||
|
||||
rockchip->msg_region = devm_ioremap(dev, rockchip->msg_bus_addr, SZ_1M);
|
||||
if (!rockchip->msg_region) {
|
||||
err = -ENOMEM;
|
||||
goto err_unmap_iospace;
|
||||
if (rockchip->deferred) {
|
||||
err = sysfs_create_group(&pdev->dev.kobj, &pcie_attr_group);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "SysFS group creation failed\n");
|
||||
goto err_unmap_iospace;
|
||||
}
|
||||
} else {
|
||||
err = rockchip_pcie_really_probe(rockchip);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "deferred probe failed\n");
|
||||
goto err_probe_dma;
|
||||
}
|
||||
}
|
||||
|
||||
list_splice_init(&res, &bridge->windows);
|
||||
bridge->dev.parent = dev;
|
||||
bridge->sysdata = rockchip;
|
||||
bridge->busnr = 0;
|
||||
bridge->ops = &rockchip_pcie_ops;
|
||||
bridge->map_irq = of_irq_parse_and_map_pci;
|
||||
bridge->swizzle_irq = pci_common_swizzle;
|
||||
if (rockchip->dma_trx_enabled == 0)
|
||||
return 0;
|
||||
|
||||
err = pci_scan_root_bus_bridge(bridge);
|
||||
if (err < 0)
|
||||
goto err_unmap_iospace;
|
||||
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_probe_dma;
|
||||
}
|
||||
|
||||
bus = bridge->bus;
|
||||
|
||||
rockchip->root_bus = bus;
|
||||
|
||||
pci_bus_size_bridges(bus);
|
||||
pci_bus_assign_resources(bus);
|
||||
list_for_each_entry(child, &bus->children, node)
|
||||
pcie_bus_configure_settings(child);
|
||||
|
||||
pci_bus_add_devices(bus);
|
||||
return 0;
|
||||
|
||||
err_probe_dma:
|
||||
if (rockchip->deferred)
|
||||
sysfs_remove_group(&pdev->dev.kobj, &pcie_attr_group);
|
||||
err_unmap_iospace:
|
||||
pci_unmap_iospace(rockchip->io);
|
||||
err_free_res:
|
||||
pci_free_resource_list(&res);
|
||||
pci_free_resource_list(&rockchip->resources);
|
||||
err_remove_irq_domain:
|
||||
irq_domain_remove(rockchip->irq_domain);
|
||||
err_deinit_port:
|
||||
rockchip_pcie_deinit_phys(rockchip);
|
||||
err_vpcie:
|
||||
if (!IS_ERR(rockchip->vpcie12v))
|
||||
regulator_disable(rockchip->vpcie12v);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_pci.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
@@ -27,6 +28,8 @@ 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 err;
|
||||
|
||||
@@ -119,9 +122,9 @@ int rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip)
|
||||
}
|
||||
|
||||
if (rockchip->is_rc) {
|
||||
rockchip->ep_gpio = devm_gpiod_get(dev, "ep", GPIOD_OUT_HIGH);
|
||||
rockchip->ep_gpio = devm_gpiod_get_optional(dev, "ep", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(rockchip->ep_gpio)) {
|
||||
dev_err(dev, "missing ep-gpios property in node\n");
|
||||
dev_err(dev, "invalid ep-gpios property in node\n");
|
||||
return PTR_ERR(rockchip->ep_gpio);
|
||||
}
|
||||
}
|
||||
@@ -150,6 +153,38 @@ int rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip)
|
||||
return PTR_ERR(rockchip->clk_pcie_pm);
|
||||
}
|
||||
|
||||
if (rockchip->is_rc) {
|
||||
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, "rockchip,dma_trx_enabled",
|
||||
&rockchip->dma_trx_enabled);
|
||||
if (err < 0) {
|
||||
dev_warn(dev,
|
||||
"missing \"rockchip,dma_trx_enabled\" property\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = of_property_read_u32(node, "rockchip,deferred",
|
||||
&rockchip->deferred);
|
||||
if (err < 0) {
|
||||
dev_warn(dev, "missing \"rockchip,deferred\" property\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rockchip_pcie_parse_dt);
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#define PCIE_CLIENT_CONF_ENABLE HIWORD_UPDATE_BIT(0x0001)
|
||||
#define PCIE_CLIENT_CONF_DISABLE HIWORD_UPDATE(0x0001, 0)
|
||||
#define PCIE_CLIENT_LINK_TRAIN_ENABLE HIWORD_UPDATE_BIT(0x0002)
|
||||
#define PCIE_CLIENT_LINK_TRAIN_DISABLE HIWORD_UPDATE(0x0002, 0x0000)
|
||||
#define PCIE_CLIENT_ARI_ENABLE HIWORD_UPDATE_BIT(0x0008)
|
||||
#define PCIE_CLIENT_CONF_LANE_NUM(x) HIWORD_UPDATE(0x0030, ENCODE_LANES(x))
|
||||
#define PCIE_CLIENT_MODE_RC HIWORD_UPDATE_BIT(0x0040)
|
||||
@@ -39,6 +40,7 @@
|
||||
#define PCIE_CLIENT_GEN_SEL_2 HIWORD_UPDATE_BIT(0x0080)
|
||||
#define PCIE_CLIENT_DEBUG_OUT_0 (PCIE_CLIENT_BASE + 0x3c)
|
||||
#define PCIE_CLIENT_DEBUG_LTSSM_MASK GENMASK(5, 0)
|
||||
#define PCIE_CLIENT_DEBUG_LTSSM_L0 0x10
|
||||
#define PCIE_CLIENT_DEBUG_LTSSM_L1 0x18
|
||||
#define PCIE_CLIENT_DEBUG_LTSSM_L2 0x19
|
||||
#define PCIE_CLIENT_BASIC_STATUS1 (PCIE_CLIENT_BASE + 0x48)
|
||||
@@ -74,7 +76,20 @@
|
||||
PCIE_CLIENT_INT_FATAL_ERR | PCIE_CLIENT_INT_DPA | \
|
||||
PCIE_CLIENT_INT_HOT_RST | PCIE_CLIENT_INT_MSG | \
|
||||
PCIE_CLIENT_INT_LEGACY_DONE | PCIE_CLIENT_INT_LEGACY | \
|
||||
PCIE_CLIENT_INT_PHY)
|
||||
PCIE_CLIENT_INT_PHY | PCIE_CLIENT_INT_UDMA)
|
||||
|
||||
#define PCIE_APB_CORE_UDMA_BASE (BIT(23) | BIT(22) | BIT(21))
|
||||
#define PCIE_CH0_DONE_ENABLE BIT(0)
|
||||
#define PCIE_CH1_DONE_ENABLE BIT(1)
|
||||
#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 \
|
||||
(PCIE_CH0_DONE_ENABLE | PCIE_CH1_DONE_ENABLE | \
|
||||
PCIE_CH0_ERR_ENABLE | PCIE_CH1_ERR_ENABLE)
|
||||
|
||||
#define PCIE_CORE_CTRL_MGMT_BASE 0x900000
|
||||
#define PCIE_CORE_CTRL (PCIE_CORE_CTRL_MGMT_BASE + 0x000)
|
||||
@@ -185,6 +200,8 @@
|
||||
#define PCIE_ECAM_ADDR(bus, dev, func, reg) \
|
||||
(PCIE_ECAM_BUS(bus) | PCIE_ECAM_DEV(dev) | \
|
||||
PCIE_ECAM_FUNC(func) | PCIE_ECAM_REG(reg))
|
||||
#define PCIE_LINK_IS_L0(x) \
|
||||
(((x) & PCIE_CLIENT_DEBUG_LTSSM_MASK) == PCIE_CLIENT_DEBUG_LTSSM_L0)
|
||||
#define PCIE_LINK_IS_L2(x) \
|
||||
(((x) & PCIE_CLIENT_DEBUG_LTSSM_MASK) == PCIE_CLIENT_DEBUG_LTSSM_L2)
|
||||
#define PCIE_LINK_UP(x) \
|
||||
@@ -275,6 +292,9 @@
|
||||
(((c) << ((b) * 8 + 5)) & \
|
||||
ROCKCHIP_PCIE_CORE_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b))
|
||||
|
||||
#define PCIE_USER_RELINK 0x1
|
||||
#define PCIE_USER_UNLINK 0x2
|
||||
|
||||
struct rockchip_pcie {
|
||||
void __iomem *reg_base; /* DT axi-base */
|
||||
void __iomem *apb_base; /* DT apb-base */
|
||||
@@ -313,6 +333,14 @@ struct rockchip_pcie {
|
||||
phys_addr_t mem_bus_addr;
|
||||
bool is_rc;
|
||||
struct resource *mem_res;
|
||||
phys_addr_t mem_reserve_start;
|
||||
size_t mem_reserve_size;
|
||||
int dma_trx_enabled;
|
||||
int deferred;
|
||||
int wait_ep;
|
||||
struct dma_trx_obj *dma_obj;
|
||||
struct list_head resources;
|
||||
struct pci_host_bridge *bridge;
|
||||
};
|
||||
|
||||
static u32 rockchip_pcie_read(struct rockchip_pcie *rockchip, u32 reg)
|
||||
|
||||
@@ -118,9 +118,9 @@
|
||||
#define PCIE_DMA_WR_BUF_SIZE (PCIE_DMA_BUF_SIZE * PCIE_DMA_BUF_CNT)
|
||||
#define PCIE_DMA_ACK_BASE (PCIE_DMA_RD_BUF_SIZE + PCIE_DMA_WR_BUF_SIZE)
|
||||
|
||||
#define PCIE_DMA_SET_DATA_CHECK_POS 0x0
|
||||
#define PCIE_DMA_SET_LOCAL_IDX_POS 0x4
|
||||
#define PCIE_DMA_SET_BUF_SIZE_POS 0x8
|
||||
#define PCIE_DMA_SET_DATA_CHECK_POS (SZ_1M - 0x4)
|
||||
#define PCIE_DMA_SET_LOCAL_IDX_POS (SZ_1M - 0x8)
|
||||
#define PCIE_DMA_SET_BUF_SIZE_POS (SZ_1M - 0xc)
|
||||
|
||||
#define PCIE_DMA_DATA_CHECK 0x12345678
|
||||
#define PCIE_DMA_DATA_ACK_CHECK 0xdeadbeef
|
||||
@@ -171,6 +171,7 @@ static void rk_pcie_prepare_dma(struct dma_trx_obj *obj,
|
||||
writel(local_idx, virt + PCIE_DMA_SET_LOCAL_IDX_POS);
|
||||
writel(buf_size, virt + PCIE_DMA_SET_BUF_SIZE_POS);
|
||||
|
||||
buf_size = SZ_1M;
|
||||
break;
|
||||
case PCIE_DMA_DATA_RCV_ACK:
|
||||
table = obj->table[PCIE_DMA_DATA_RCV_ACK_TABLE_OFFSET + idx];
|
||||
@@ -306,7 +307,7 @@ static enum hrtimer_restart rk_pcie_scan_timer(struct hrtimer *timer)
|
||||
if (sdv == PCIE_DMA_DATA_CHECK) {
|
||||
if (!need_ack)
|
||||
need_ack = true;
|
||||
writel(0x0, scan_data_addr);
|
||||
writel(0x0, scan_data_addr + PCIE_DMA_SET_DATA_CHECK_POS);
|
||||
set_bit(i, &obj->local_read_available);
|
||||
rk_pcie_prepare_dma(obj, idx, 0, 0, 0x4,
|
||||
PCIE_DMA_DATA_RCV_ACK);
|
||||
@@ -361,6 +362,12 @@ static int rk_pcie_misc_open(struct inode *inode, struct file *filp)
|
||||
|
||||
filp->private_data = pcie_misc_dev->obj;
|
||||
|
||||
pcie_misc_dev->obj->loop_count = 0;
|
||||
pcie_misc_dev->obj->local_read_available = 0x0;
|
||||
pcie_misc_dev->obj->local_write_available = 0xff;
|
||||
pcie_misc_dev->obj->remote_write_available = 0xff;
|
||||
pcie_misc_dev->obj->dma_free = true;
|
||||
|
||||
pr_info("Open pcie misc device success\n");
|
||||
|
||||
return 0;
|
||||
@@ -687,10 +694,6 @@ struct dma_trx_obj *rk_pcie_dma_obj_probe(struct device *dev)
|
||||
if (ret)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
obj->local_read_available = 0x0;
|
||||
obj->remote_write_available = 0xff;
|
||||
obj->local_write_available = 0xff;
|
||||
|
||||
obj->dma_trx_wq = create_singlethread_workqueue("dma_trx_wq");
|
||||
INIT_WORK(&obj->dma_trx_work, rk_pcie_dma_trx_work);
|
||||
|
||||
@@ -710,9 +713,7 @@ struct dma_trx_obj *rk_pcie_dma_obj_probe(struct device *dev)
|
||||
goto free_dma_table;
|
||||
}
|
||||
|
||||
obj->dma_free = true;
|
||||
obj->irq_num = 0;
|
||||
obj->loop_count = 0;
|
||||
obj->loop_count_threshold = 0;
|
||||
init_completion(&obj->done);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user