Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add embedded SoC FPGA support #115

Draft
wants to merge 12 commits into
base: intel/fpga-ofs-dev-6.6-lts
Choose a base branch
from
Draft
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
9 changes: 9 additions & 0 deletions Documentation/ABI/testing/sysfs-bus-dfl
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,12 @@ Description: Read-only. It returns feature identifier local to its DFL FIU
type.

Format: 0x%x

What: /sys/bus/dfl/devices/dfl_dev.X/guid
Date: Nov 2023
KernelVersion: 6.6
Contact: Basheer Ahmed Muddebihal <[email protected]>
Description: Read-only. It returns DFL feature identifier in the form GUID
(8-4-4-4-12) if the feature header version is 1(DFHv1).

Format: 03020100-0504-0706-0809-0A0B0C0D0E0F (Little Endian)
12 changes: 6 additions & 6 deletions Documentation/devicetree/bindings/soc/intel/intel,dfl-mmio.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,19 @@ properties:
This property establishes a reference to the Interrupt Controller Node,
which manages interrupts for the device.

interrupt-user-start:
intel,user-interrupt-start:
maxItems: 1
description:
This property defines the initial user interrupts available on the specified
controller. GIC are reserved for local purposes

fpga-interrupt-start:
intel,fpga-interrupt-start:
maxItems: 1
descritpion:
This property indicates the starting interrupt number within the GIC where
FPGA-specific interrupts are mapped.

fpga-interrupt-lines:
intel,fpga-interrupt-lines:
maxItems: 1
descritpions:
This property specifies the total count of Interrupt Requests (IRQs)
Expand All @@ -61,7 +61,7 @@ examples:
compatible = "intel,dfl-mmio";
reg = <0xF9000000 0x00002000>;
interrupt-parent = <&intc>;
interrupt-user-start = <32>;
fpga-interrupt-start = <49>;
fpga-interrupt-lines = <64>;
intel,user-interrupt-start = <32>;
intel,fpga-interrupt-start = <49>;
intel,fpga-interrupt-lines = <64>;
};
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,11 @@ endif
# The module order matters; it determines the module order for
# both the insmod and rmmod targets. The module order is also
# leveraged for install packages by the dkms.conf file.
ifneq ($(CONFIG_FPGA),y)
obj-m += fpga-mgr.o
obj-m += fpga-bridge.o
obj-m += fpga-region.o
endif
ifndef CONFIG_FW_UPLOAD
obj-m += fpga-image-load.o
endif
Expand All @@ -61,6 +63,7 @@ obj-m += dfl-fme-mgr.o
obj-m += dfl-fme-region.o
obj-m += dfl-fme-br.o
obj-m += dfl-priv-feat.o
obj-m += dfl-branch.o
obj-m += dfl-hssi.o
obj-m += dfl-n3000-nios.o
obj-m += dfl-emif.o
Expand Down Expand Up @@ -107,6 +110,7 @@ dfl-fme-y += drivers/fpga/dfl-fme-perf.o
dfl-fme-y += drivers/fpga/dfl-fme-error.o

dfl-priv-feat-y += drivers/fpga/dfl-priv-feat-main.o
dfl-branch-y += drivers/fpga/dfl-branch.o

dfl-fme-br-y := drivers/fpga/dfl-fme-br.o
dfl-fme-mgr-y := drivers/fpga/dfl-fme-mgr.o
Expand Down
11 changes: 11 additions & 0 deletions drivers/fpga/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,17 @@ config FPGA_DFL_PRIV_FEAT
To compile this driver as a module, choose M here: the module will
be called dfl_priv_feat.

config FPGA_DFL_BRANCH
tristate "FPGA DFL Branch Driver"
depends on FPGA_DFL
help
This is the feature driver for Branch DFL (Device Feature List),
which binds the DFL driver for the branch DFL feature using GUID,
and processes branch parameters and enumerates DFL devices in
the branch list.

To compile this as a module, choose M here.

config FPGA_DFL_NIOS_INTEL_PAC_N3000
tristate "FPGA DFL NIOS Driver for Intel PAC N3000"
depends on FPGA_DFL
Expand Down
1 change: 1 addition & 0 deletions drivers/fpga/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ obj-$(CONFIG_OF_FPGA_REGION) += of-fpga-region.o

# FPGA Device Feature List Support
obj-$(CONFIG_FPGA_DFL) += dfl.o
obj-$(CONFIG_FPGA_DFL_BRANCH) += dfl-branch.o
obj-$(CONFIG_FPGA_DFL_FME) += dfl-fme.o
obj-$(CONFIG_FPGA_DFL_PRIV_FEAT) += dfl-priv-feat.o
obj-$(CONFIG_FPGA_DFL_FME_MGR) += dfl-fme-mgr.o
Expand Down
166 changes: 166 additions & 0 deletions drivers/fpga/dfl-branch.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Driver for FPGA BRANCH DFL
*
* Copyright (C) 2023 Intel Corporation.
*
* Authors:
* Basheer Ahmed Muddebihal <[email protected]>
*/

#include <linux/bitfield.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/types.h>

#include "dfl.h"

#define DRV_NAME "dfl-branch"

#define DFHv1_PARAM_ID_BRANCH_DFL 0xF00C
#define DFL_BRANCH_SIZE 0x2000 /*default DFL ROM Size*/
#define DFL_BRANCH_PARAM_DATA_LEN 16 /*two 8-byte words*/

/*
* REL_N, 1'b0 = relative (offset from feature DFH start),
* 1'b1 = absolute (ARM or other non-PCIe use)
*/
#define DFHv1_BRANCH_DFL_ADDR_REL_N BIT_ULL(0)
#define DFHv1_BRANCH_DFL_ADDR GENMASK_ULL(63, 3) /* 63:3 of DFL address */
#define DFHv1_BRANCH_DFL_SIZE GENMASK_ULL(63, 32) /* 63:32 size of DFL */

static int dfh_branch_get_param_vals(struct dfl_device *dfl_dev, int param_id,
u64 *bdfl_addr, size_t *bdfl_size, bool *rel_addr)
{
struct device *dev = &dfl_dev->dev;
u64 addr_val, size_val;
size_t psize;
u64 *p;

p = dfh_find_param(dfl_dev, param_id, &psize);
if (IS_ERR(p))
return PTR_ERR(p);

if (psize == DFL_BRANCH_PARAM_DATA_LEN) {
addr_val = *p;
size_val = *(p + 1);
dev_info(dev, "addr_val = %pa, size_val=%pa\n", &addr_val, &size_val);
} else {
dev_err(dev, "Branch parameters data is missing\n");
return -EINVAL;
}

if (FIELD_GET(DFHv1_BRANCH_DFL_ADDR_REL_N, addr_val))
*rel_addr = false;
else
*rel_addr = true;

*bdfl_addr = FIELD_GET(DFHv1_BRANCH_DFL_ADDR, addr_val) << 3;
*bdfl_size = FIELD_GET(DFHv1_BRANCH_DFL_SIZE, size_val);

return 0;
}

static int dfl_branch_process_dfl(struct dfl_device *dfl_dev)
{
struct device *dev = &dfl_dev->dev;
struct dfl_fpga_enum_info *info;
struct dfl_fpga_cdev *cdev;
resource_size_t start, len;
resource_size_t feat_base;
bool rel_addr = true;
u64 *pstart, *pend;
size_t bdfl_size;
u64 bdfl_addr;
u64 next, v;
int ret;

/* allocate enumeration info */
info = dfl_fpga_enum_info_alloc(dev);
if (!info)
return -ENOMEM;

pstart = dfl_dev->params;
pend = dfl_dev->params + dfl_dev->param_size / sizeof(u64);

feat_base = dfl_dev->mmio_res.start;

while (pstart < pend) {
v = *pstart;

ret = dfh_branch_get_param_vals(dfl_dev, DFHv1_PARAM_ID_BRANCH_DFL,
&bdfl_addr, &bdfl_size, &rel_addr);

if (!ret) {
if (rel_addr) {
start = feat_base + bdfl_addr;
dev_info(dev, "Start=%pa\n", &start);
} else {
start = bdfl_addr;
}

len = bdfl_size ? bdfl_size : DFL_BRANCH_SIZE;
dfl_fpga_enum_info_add_dfl(info, start, len);
}
next = FIELD_GET(DFHv1_PARAM_HDR_NEXT_OFFSET, v);
pstart += next;
}

/* start enumeration with prepared enumeration information */
cdev = dfl_fpga_feature_devs_enumerate(info);
if (IS_ERR(cdev)) {
dev_err(&dfl_dev->dev, "Enumeration failure\n");
ret = PTR_ERR(cdev);
goto info_free_exit;
}

dfl_dev->cdev = cdev;

info_free_exit:
dfl_fpga_enum_info_free(info);

return ret;
}

static int dfl_branch_probe(struct dfl_device *dfl_dev)
{
struct device *dev = &dfl_dev->dev;
int ret;

ret = dfl_branch_process_dfl(dfl_dev);
if (ret < 0)
return dev_err_probe(dev, ret, "Failed to find the branch dfl\n");

return 0;
}

static void dfl_branch_remove(struct dfl_device *dfl_dev)
{
dfl_fpga_feature_devs_remove(dfl_dev->cdev);
}

#define DFL_BRANCH_GUID "30C45AEA-68F6-42E6-AEFB-15B4B5E28284"

static const struct dfl_device_id dfl_branch_ids[] = {
{ .guid_string = DFL_BRANCH_GUID },
{ }
};
MODULE_DEVICE_TABLE(dfl, dfl_branch_ids);

static struct dfl_driver dfl_branch_driver = {
.drv = {
.name = "dfl-branch",
},
.id_table = dfl_branch_ids,
.probe = dfl_branch_probe,
.remove = dfl_branch_remove,
};
module_dfl_driver(dfl_branch_driver);

MODULE_ALIAS("dfl:t*f*g{" DFL_BRANCH_GUID "}");
MODULE_DESCRIPTION("DFL Intel Branch DFL driver");
MODULE_AUTHOR("Intel Corporation");
MODULE_LICENSE("GPL");
39 changes: 37 additions & 2 deletions drivers/fpga/dfl-platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@

#define DRV_NAME "dfl-platform"

#define USER_INTERRUPT_START 32
#define FPGA_INTERRUPT_START 49
#define FPGA_INTERRUPT_LINES 64

struct dfl_platform_drvdata {
struct dfl_fpga_cdev *cdev; /* container device */
};
Expand All @@ -37,6 +41,34 @@ static int dfl_platform_init_drvdata(struct platform_device *pdev)
return 0;
}

static void dfl_platform_process_intr_params(struct platform_device *pdev,
struct dfl_fpga_enum_info *info)
{
struct device_node *node = pdev->dev.of_node;
int user_intr_start = USER_INTERRUPT_START;
int fpga_intr_start = FPGA_INTERRUPT_START;
int fpga_intr_lines = FPGA_INTERRUPT_LINES;
int reg;

if (of_property_read_u32(node, "intel,user-interrupt-start", &reg))
dev_warn(&pdev->dev, "intel,user-interrupt-start value not set in device tree\n");
else
user_intr_start = reg;

if (of_property_read_u32(node, "intel,fpga-interrupt-start", &reg))
dev_warn(&pdev->dev, "intel,fpga-interrupt-start not set in device tree\n");
else
fpga_intr_start = reg;

if (of_property_read_u32(node, "intel,fpga-interrupt-lines", &reg))
dev_warn(&pdev->dev, "intel,interrupt-user-offset value not set in device tree\n");
else
fpga_intr_lines = reg;

info->gic_arm_ref = fpga_intr_start - user_intr_start;
info->fpga_intr_lines = fpga_intr_lines;
}

static void dfl_platform_remove_feature_devs(struct platform_device *pdev)
{
struct dfl_platform_drvdata *drvdata = platform_get_drvdata(pdev);
Expand Down Expand Up @@ -68,6 +100,8 @@ static int dfl_platform_process_dfl_node(struct platform_device *pdev,
goto err_map;
}

dfl_platform_process_intr_params(pdev, info);

dfl_fpga_enum_info_add_dfl(info, start, len);

/* release I/O mappings for next step enumeration */
Expand Down Expand Up @@ -113,6 +147,7 @@ static int dfl_platform_enumerate_feature_devs(struct platform_device *pdev,
return ret;
}


static int dfl_platform_probe(struct platform_device *pdev)
{
struct resource dfl_location;
Expand Down Expand Up @@ -163,13 +198,13 @@ static int dfl_platform_remove(struct platform_device *pdev)

static const struct of_device_id dfl_platform_match[] = {
{ .compatible = "intel,dfl-mmio", },
{},
{}
};
MODULE_DEVICE_TABLE(of, dfl_platform_match);

static const struct platform_device_id dfl_platform_ids[] = {
{ DRV_NAME, 0 },
{ }
{}
};
MODULE_DEVICE_TABLE(platform, dfl_platform_ids);

Expand Down
20 changes: 15 additions & 5 deletions drivers/fpga/dfl-priv-feat-main.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,29 @@
#include "dfl.h"
#include "dfl-priv-feat.h"

static ssize_t
guid_show(struct device *dev, struct device_attribute *attr, char *buf)
static ssize_t group_id_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct dfl_device *ddev = to_dfl_dev(dev);
if (!ddev->dfh_version)
return -ENOENT;

return sysfs_emit(buf, "0x%X\n", ddev->group_id);
}
static DEVICE_ATTR_RO(group_id);

static ssize_t inst_id_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct dfl_device *ddev = to_dfl_dev(dev);
if (!ddev->dfh_version)
return -ENOENT;

return sysfs_emit(buf, "%pUL\n", &ddev->guid);
return sysfs_emit(buf, "0x%X\n", ddev->inst_id);
}
static DEVICE_ATTR_RO(guid);
static DEVICE_ATTR_RO(inst_id);

static struct attribute *dfl_priv_feat_attrs[] = {
&dev_attr_guid.attr,
&dev_attr_group_id.attr,
&dev_attr_inst_id.attr,
NULL,
};

Expand Down Expand Up @@ -129,3 +138,4 @@ module_platform_driver(dfl_priv_feat_driver);
MODULE_DESCRIPTION("FPGA Privare Feature driver");
MODULE_AUTHOR("Intel Corporation");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:dfl-priv-feat");
Loading