Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions arch/arm/boot/dts/xilinx/ni-zynq.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@
clock-frequency = <58824000>;
};

fpgaperipheral@f8007000 {
compatible = "fpgaperipheral";
reg = <0xf8007000 0x100>;
};

i2c2: i2c@81000000 {
compatible = "xlnx,xps-iic-2.00.a";
status = "disabled";
Expand Down Expand Up @@ -173,6 +178,14 @@
arm,standby-mode = <0>;
};

&devcfg {
status = "disabled";
};

&fpga_full {
status = "disabled";
};

/*
* The CoreSight debug/trace macrocells are not accessible on NI Zynq-based
* targets: reading their AMBA peripheral-ID registers (done unconditionally
Expand Down
1 change: 1 addition & 0 deletions arch/arm/configs/nati_zynq_defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ CONFIG_EXPERT=y
CONFIG_PERF_EVENTS=y
CONFIG_ARCH_VEXPRESS=y
CONFIG_ARCH_ZYNQ=y
CONFIG_NI_ZYNQ_GIC_LEGACY_IRQDOMAIN=y
CONFIG_ARM_ERRATA_754322=y
CONFIG_ARM_ERRATA_764369=y
CONFIG_ARM_ERRATA_775420=y
Expand Down
10 changes: 10 additions & 0 deletions arch/arm/mach-zynq/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,13 @@ config ARCH_ZYNQ
select SOC_BUS
help
Support for Xilinx Zynq ARM Cortex A9 Platform

config NI_ZYNQ_GIC_LEGACY_IRQDOMAIN
bool "Use fixed GIC IRQ numbers on NI Zynq targets"
depends on ARCH_ZYNQ
help
Create fixed Linux IRQ mappings for the primary GIC so that its
Linux IRQ numbers equal the corresponding GIC hardware IRQ numbers.
This preserves compatibility with NI drivers that use fixed IRQs.
Enable this only on NI Zynq systems that require the legacy IRQ
numbering contract.
71 changes: 68 additions & 3 deletions drivers/irqchip/irq-gic.c
Original file line number Diff line number Diff line change
Expand Up @@ -1160,6 +1160,73 @@ static const struct irq_domain_ops gic_irq_domain_hierarchy_ops = {
.free = irq_domain_free_irqs_top,
};

static const struct irq_domain_ops gic_irq_domain_legacy_ops = {
.map = gic_irq_domain_map,
.translate = gic_irq_domain_translate,
.alloc = gic_irq_domain_alloc,
.free = irq_domain_free_irqs_top,
};

static struct irq_domain *gic_create_irq_domain(struct gic_chip_data *gic,
struct fwnode_handle *handle,
unsigned int gic_irqs)
{
struct irq_domain *domain;
unsigned int irq_count;
unsigned int irq;
int irq_base;

if (!IS_ENABLED(CONFIG_NI_ZYNQ_GIC_LEGACY_IRQDOMAIN) ||
gic != &gic_data[0])
return irq_domain_create_linear(handle, gic_irqs,
&gic_irq_domain_hierarchy_ops,
gic);

if (gic_irqs <= NR_IRQS_LEGACY)
return NULL;

irq_count = gic_irqs - NR_IRQS_LEGACY;
Comment thread
gratian marked this conversation as resolved.
irq_base = irq_alloc_descs(NR_IRQS_LEGACY, NR_IRQS_LEGACY,
irq_count, numa_node_id());
if (irq_base != NR_IRQS_LEGACY) {
if (irq_base >= 0)
irq_free_descs(irq_base, irq_count);
pr_err("GIC: cannot reserve fixed IRQ range %u-%u (%d)\n",
NR_IRQS_LEGACY, gic_irqs - 1, irq_base);
return NULL;
}

domain = irq_domain_create_legacy(handle, irq_count, NR_IRQS_LEGACY,
NR_IRQS_LEGACY,
&gic_irq_domain_legacy_ops, gic);
if (!domain) {
irq_free_descs(irq_base, irq_count);
return NULL;
}

for (irq = NR_IRQS_LEGACY; irq < gic_irqs; irq++) {
if (irq_find_mapping(domain, irq) != irq) {
unsigned int mapped_irq;

pr_err("GIC: failed to establish fixed mapping for IRQ%u\n",
irq);
for (mapped_irq = NR_IRQS_LEGACY;
mapped_irq < gic_irqs; mapped_irq++) {
if (irq_find_mapping(domain, mapped_irq) == mapped_irq)
irq_dispose_mapping(mapped_irq);
else
irq_free_desc(mapped_irq);
}
irq_domain_remove(domain);
return NULL;
Comment thread
gratian marked this conversation as resolved.
}
}

pr_info("GIC: using fixed Linux IRQ mapping %u-%u\n",
NR_IRQS_LEGACY, gic_irqs - 1);
return domain;
}

static int gic_init_bases(struct gic_chip_data *gic,
struct fwnode_handle *handle)
{
Expand Down Expand Up @@ -1207,9 +1274,7 @@ static int gic_init_bases(struct gic_chip_data *gic,
gic_irqs = 1020;
gic->gic_irqs = gic_irqs;

gic->domain = irq_domain_create_linear(handle, gic_irqs,
&gic_irq_domain_hierarchy_ops,
gic);
gic->domain = gic_create_irq_domain(gic, handle, gic_irqs);
if (WARN_ON(!gic->domain)) {
ret = -ENODEV;
goto error;
Expand Down
7 changes: 0 additions & 7 deletions drivers/net/ethernet/cadence/macb_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -4487,7 +4487,6 @@ static const struct net_device_ops macb_netdev_ops = {
static int macb_fpga_notifier(struct notifier_block *nb, unsigned long val, void *data)
{
struct macb *bp = container_of(nb, struct macb, fpga_notifier);
struct net_device *dev = bp->dev;

switch (val) {
case FPGA_PERIPHERAL_DOWN:
Expand All @@ -4501,9 +4500,6 @@ static int macb_fpga_notifier(struct notifier_block *nb, unsigned long val, void
if (netif_running(bp->dev)) {
dev_deactivate(bp->dev);
macb_close(bp->dev);
if (phy_interrupt_is_valid(dev->phydev))
phy_free_interrupt(dev->phydev);
phy_stop_machine_nolink(dev->phydev);
}

bp->fpga_down = 1;
Expand All @@ -4524,9 +4520,6 @@ static int macb_fpga_notifier(struct notifier_block *nb, unsigned long val, void

/* If the interface has been opened. */
if (netif_running(bp->dev)) {
phy_start_machine(dev->phydev);
if (phy_interrupt_is_valid(dev->phydev))
phy_request_interrupt(dev->phydev);
macb_open(bp->dev);
dev_activate(bp->dev);
}
Expand Down
74 changes: 74 additions & 0 deletions drivers/tty/serial/8250/8250_ni.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,17 @@
#include <linux/init.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/notifier.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/serial_core.h>
#include <linux/types.h>

#ifdef CONFIG_FPGA_PERIPHERAL
#include <misc/fpgaperipheral.h>
#endif

#include "8250.h"

/* Extra bits in UART_ACR */
Expand Down Expand Up @@ -77,8 +82,58 @@ struct ni16550_device_info {
struct ni16550_data {
int line;
struct clk *clk;
#ifdef CONFIG_FPGA_PERIPHERAL
struct notifier_block fpga_notifier;
bool fpga_notifier_registered;
bool fpga_suspended;
#endif
};

#ifdef CONFIG_FPGA_PERIPHERAL
static u32 ni16550_disabled_serial_in(struct uart_port *port,
unsigned int offset)
{
return 0;
}

static void ni16550_disabled_serial_out(struct uart_port *port,
unsigned int offset, u32 value)
{
}

static int ni16550_fpga_notify(struct notifier_block *nb,
unsigned long event, void *unused)
{
struct ni16550_data *data = container_of(nb, struct ni16550_data,
fpga_notifier);
struct uart_8250_port *uart = serial8250_get_port(data->line);
Comment thread
gratian marked this conversation as resolved.

switch (event) {
case FPGA_PERIPHERAL_DOWN:
if (!data->fpga_suspended) {
serial8250_suspend_port(data->line);
uart->port.serial_in = ni16550_disabled_serial_in;
uart->port.serial_out = ni16550_disabled_serial_out;
data->fpga_suspended = true;
}
break;
case FPGA_PERIPHERAL_UP:
if (data->fpga_suspended) {
serial8250_set_defaults(uart);
serial8250_resume_port(data->line);
data->fpga_suspended = false;
}
break;
case FPGA_PERIPHERAL_FAILED:
Comment thread
gratian marked this conversation as resolved.
break;
default:
return NOTIFY_DONE;
}

return NOTIFY_OK;
}
#endif

static int ni16550_enable_transceivers(struct uart_port *port)
{
u8 pcr;
Expand Down Expand Up @@ -405,6 +460,20 @@ static int ni16550_probe(struct platform_device *pdev)
return ret;
data->line = ret;

#ifdef CONFIG_FPGA_PERIPHERAL
if (dev_of_node(dev)) {
data->fpga_notifier.notifier_call = ni16550_fpga_notify;
ret = blocking_notifier_chain_register(&fpgaperipheral_notifier_list,
&data->fpga_notifier);
if (ret) {
serial8250_unregister_port(data->line);
return dev_err_probe(dev, ret,
"failed to register FPGA notifier\n");
}
data->fpga_notifier_registered = true;
}
#endif

platform_set_drvdata(pdev, data);
return 0;
}
Expand All @@ -413,6 +482,11 @@ static void ni16550_remove(struct platform_device *pdev)
{
struct ni16550_data *data = platform_get_drvdata(pdev);

#ifdef CONFIG_FPGA_PERIPHERAL
if (data->fpga_notifier_registered)
blocking_notifier_chain_unregister(&fpgaperipheral_notifier_list,
&data->fpga_notifier);
#endif
serial8250_unregister_port(data->line);
}

Expand Down
Loading