Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
S
Simple PCIe FMC carrier SPEC
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
50
Issues
50
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
image/svg+xml
Discourse
Discourse
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Projects
Simple PCIe FMC carrier SPEC
Commits
b611a1df
Commit
b611a1df
authored
May 14, 2019
by
Federico Vaga
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
drv: introduce FMC layer
Signed-off-by:
Federico Vaga
<
federico.vaga@cern.ch
>
parent
62bb82a1
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
199 additions
and
1 deletion
+199
-1
Kbuild
kernel/Kbuild
+6
-0
Makefile
kernel/Makefile
+3
-1
spec-core.c
kernel/spec-core.c
+6
-0
spec-fmc.c
kernel/spec-fmc.c
+176
-0
spec.h
kernel/spec.h
+8
-0
No files found.
kernel/Kbuild
View file @
b611a1df
...
...
@@ -16,11 +16,16 @@ ccflags-y += -Wall -Werror
ccflags-$(CONFIG_FPGA_MGR_BACKPORT) += -DCONFIG_FPGA_MGR_BACKPORT
ccflags-$(CONFIG_FPGA_MGR_BACKPORT) += $(CONFIG_FPGA_MGR_BACKPORT_INCLUDE)
ccflags-y += -I$(FMC_ABS)/include
# priority to I2C, FMC headers from our sources
LINUXINCLUDE := -I$(FMC_ABS)/include -I$(FMC_ABS)/include/linux -I$(I2C_ABS)/include -I$(I2C_ABS)/include/linux $(LINUXINCLUDE)
ifeq ($(CONFIG_FPGA_MGR_BACKPORT), y)
LINUXINCLUDE := $(CONFIG_FPGA_MGR_BACKPORT_INCLUDE) $(LINUXINCLUDE)
KBUILD_EXTRA_SYMBOLS += $(CONFIG_FPGA_MGR_BACKPORT_PATH_ABS)/drivers/fpga/Module.symvers
endif
KBUILD_EXTRA_SYMBOLS += $(FMC_ABS)/drivers/fmc/Module.symvers
obj-m := spec.o
...
...
@@ -28,4 +33,5 @@ spec-objs := spec-core.o
spec-objs += spec-fpga.o
spec-objs += spec-irq.o
spec-objs += spec-dbg.o
spec-objs += spec-fmc.o
spec-objs += spec-compat.o
kernel/Makefile
View file @
b611a1df
...
...
@@ -7,6 +7,8 @@ KVERSION ?= $(shell uname -r)
LINUX
?=
/lib/modules/
$(KVERSION)
/build
CONFIG_FPGA_MGR_BACKPORT_PATH_ABS
?=
$
(
abspath
$(CONFIG_FPGA_MGR_BACKPORT_PATH)
)
FMC_ABS
?=
$
(
abspath
$(FMC)
)
I2C_ABS
?=
$
(
abspath
$(I2C)
)
VERSION
=
$(
shell
git describe
--dirty
--long
--tags
)
...
...
@@ -15,7 +17,7 @@ all: modules
.PHONY
:
all modules clean help install modules_install
modules help install modules_install
:
$(MAKE)
-C
$(LINUX)
M
=
$(
shell
pwd
)
VERSION
=
$(VERSION)
CONFIG_FPGA_MGR_BACKPORT_PATH_ABS
=
$(CONFIG_FPGA_MGR_BACKPORT_PATH_ABS)
CONFIG_FPGA_MGR_BACKPORT
=
$(CONFIG_FPGA_MGR_BACKPORT)
$@
$(MAKE)
-C
$(LINUX)
M
=
$(
shell
pwd
)
VERSION
=
$(VERSION)
CONFIG_FPGA_MGR_BACKPORT_PATH_ABS
=
$(CONFIG_FPGA_MGR_BACKPORT_PATH_ABS)
CONFIG_FPGA_MGR_BACKPORT
=
$(CONFIG_FPGA_MGR_BACKPORT)
FMC_ABS
=
$(FMC_ABS)
I2C_ABS
=
$(I2C_ABS)
$@
# be able to run the "clean" rule even if $(LINUX) is not valid
clean
:
...
...
kernel/spec-core.c
View file @
b611a1df
...
...
@@ -156,6 +156,10 @@ static int spec_probe(struct pci_dev *pdev,
if
(
err
)
goto
err_fw
;
err
=
spec_fmc_init
(
spec
);
if
(
err
)
goto
err_fmc
;
pci_set_drvdata
(
pdev
,
spec
);
dev_info
(
spec
->
dev
.
parent
,
"Spec registered devptr=0x%p
\n
"
,
spec
->
dev
.
parent
);
...
...
@@ -163,6 +167,7 @@ static int spec_probe(struct pci_dev *pdev,
return
0
;
err_fmc:
err_fw:
spec_irq_exit
(
spec
);
err_irq:
...
...
@@ -189,6 +194,7 @@ static void spec_remove(struct pci_dev *pdev)
int
i
;
spec_dbg_exit
(
spec
);
spec_fmc_exit
(
spec
);
spec_irq_exit
(
spec
);
spec_fpga_exit
(
spec
);
...
...
kernel/spec-fmc.c
0 → 100644
View file @
b611a1df
// SPDX-License-Identifier: GPLv2
/*
* Copyright (C) 2019 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
*/
#include <linux/bitops.h>
#include <linux/fmc.h>
#include <linux/platform_data/i2c-ocores.h>
#include "spec.h"
#include "spec-compat.h"
#define SPEC_FMC_SLOTS 1
#define SPEC_I2C_SIZE 32
#define SPEC_I2C_ADDR_START 0x14000
#define SPEC_I2C_ADDR_END ((SPEC_I2C_ADDR_START + SPEC_I2C_SIZE) - 1)
static
inline
u8
spec_fmc_slot_nr
(
struct
spec_dev
*
spec
)
{
return
(
ioread32be
(
spec
->
remap
[
0
]
+
0x0
)
&
0x1
);
}
static
inline
u8
spec_fmc_presence
(
struct
spec_dev
*
spec
)
{
return
(
ioread32
(
spec
->
remap
[
0
]
+
0x0
)
&
0x1
);
}
static
int
spec_fmc_is_present
(
struct
fmc_carrier
*
carrier
,
struct
fmc_slot
*
slot
)
{
struct
spec_dev
*
spec
=
carrier
->
priv
;
return
(
spec_fmc_presence
(
spec
)
&
BIT
(
slot
->
ga
));
}
static
const
struct
fmc_carrier_operations
spec_fmc_ops
=
{
.
owner
=
THIS_MODULE
,
.
is_present
=
spec_fmc_is_present
,
};
static
const
struct
ocores_i2c_platform_data
pdata
=
{
.
reg_shift
=
2
,
/* 32bit aligned */
.
reg_io_width
=
4
,
.
clock_khz
=
62500
,
.
big_endian
=
1
,
.
num_devices
=
0
,
.
devices
=
NULL
,
};
static
int
id
;
/**
* It builds the platform_device_info necessary to register the
* I2C master device.
* @spec the SPEC instance
*
* Return: an array of I2C master devices
*/
static
int
spec_i2c_add
(
struct
spec_dev
*
spec
)
{
struct
resource
res
=
{
.
name
=
"i2c-ocores-mem"
,
.
flags
=
IORESOURCE_MEM
,
.
start
=
pci_resource_start
(
to_pci_dev
(
spec
->
dev
.
parent
),
0
)
+
SPEC_I2C_ADDR_START
,
.
end
=
pci_resource_start
(
to_pci_dev
(
spec
->
dev
.
parent
),
0
)
+
SPEC_I2C_ADDR_END
,
};
/* FIXME find better ID */
spec
->
i2c_pdev
=
platform_device_register_resndata
(
spec
->
dev
.
parent
,
"i2c-ohwr"
,
id
++
,
&
res
,
1
,
&
pdata
,
sizeof
(
pdata
));
if
(
!
spec
->
i2c_pdev
)
return
-
ENODEV
;
return
0
;
}
static
void
spec_i2c_del
(
struct
spec_dev
*
spec
)
{
if
(
spec
->
i2c_pdev
)
platform_device_unregister
(
spec
->
i2c_pdev
);
}
static
int
spec_i2c_find_adapter
(
struct
device
*
dev
,
void
*
data
)
{
struct
spec_dev
*
spec
=
data
;
struct
i2c_adapter
*
adap
,
*
adap_parent
;
if
(
dev
->
type
!=
&
i2c_adapter_type
)
return
0
;
adap
=
to_i2c_adapter
(
dev
);
adap_parent
=
i2c_parent_is_i2c_adapter
(
adap
);
if
(
!
adap_parent
)
return
0
;
/* We have a muxed I2C master */
if
(
&
spec
->
i2c_pdev
->
dev
!=
adap_parent
->
dev
.
parent
)
return
0
;
/* Found! Return the bus ID */
return
i2c_adapter_id
(
adap
);
}
/**
* Get the I2C adapter associated with an FMC slot
* @data: data used to find the correct I2C bus
* @slot_nr: FMC slot number
*
* Return: the I2C bus to be used
*/
static
int
spec_i2c_get_bus
(
struct
spec_dev
*
spec
)
{
return
i2c_for_each_dev
(
spec
,
spec_i2c_find_adapter
);
}
/**
* Create an FMC interface
*/
int
spec_fmc_init
(
struct
spec_dev
*
spec
)
{
int
err
;
pr_info
(
"%s:%d
\n
"
,
__func__
,
__LINE__
);
if
(
spec_fmc_slot_nr
(
spec
)
!=
SPEC_FMC_SLOTS
)
{
dev_err
(
spec
->
dev
.
parent
,
"Invalid SPEC FPGA (slot count: %d)
\n
"
,
spec_fmc_slot_nr
(
spec
));
return
-
EINVAL
;
}
pr_info
(
"%s:%d
\n
"
,
__func__
,
__LINE__
);
err
=
spec_i2c_add
(
spec
);
if
(
err
)
goto
err_i2c
;
pr_info
(
"%s:%d
\n
"
,
__func__
,
__LINE__
);
spec
->
slot_info
.
i2c_bus_nr
=
spec_i2c_get_bus
(
spec
);
if
(
spec
->
slot_info
.
i2c_bus_nr
<=
0
)
goto
err_i2c_bus
;
spec
->
slot_info
.
ga
=
0
;
spec
->
slot_info
.
lun
=
1
;
pr_info
(
"%s:%d
\n
"
,
__func__
,
__LINE__
);
err
=
fmc_carrier_register
(
&
spec
->
dev
,
&
spec_fmc_ops
,
spec_fmc_slot_nr
(
spec
),
&
spec
->
slot_info
,
spec
);
if
(
err
)
{
dev_err
(
spec
->
dev
.
parent
,
"Failed to register as FMC carrier
\n
"
);
goto
err_fmc
;
}
return
0
;
err_fmc:
err_i2c_bus:
spec_i2c_del
(
spec
);
err_i2c:
return
-
1
;
}
void
spec_fmc_exit
(
struct
spec_dev
*
spec
)
{
int
err
;
err
=
fmc_carrier_unregister
(
&
spec
->
dev
);
if
(
err
)
dev_err
(
spec
->
dev
.
parent
,
"Failed to unregister from FMC
\n
"
);
spec_i2c_del
(
spec
);
}
kernel/spec.h
View file @
b611a1df
...
...
@@ -16,6 +16,7 @@
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/fmc.h>
#define SPEC_FMC_SLOTS 1
...
...
@@ -128,6 +129,10 @@ struct spec_dev {
DECLARE_BITMAP
(
flags
,
SPEC_FLAG_BITS
);
void
__iomem
*
remap
[
3
];
/* ioremap of bar 0, 2, 4 */
struct
platform_device
*
i2c_pdev
;
struct
i2c_adapter
*
i2c_adapter
;
struct
fmc_slot_info
slot_info
;
struct
dentry
*
dbg_dir
;
#define SPEC_DBG_INFO_NAME "info"
struct
dentry
*
dbg_info
;
...
...
@@ -193,4 +198,7 @@ extern void spec_irq_exit(struct spec_dev *spec);
extern
int
spec_dbg_init
(
struct
spec_dev
*
spec
);
extern
void
spec_dbg_exit
(
struct
spec_dev
*
spec
);
extern
int
spec_fmc_init
(
struct
spec_dev
*
spec
);
extern
void
spec_fmc_exit
(
struct
spec_dev
*
spec
);
#endif
/* __SPEC_H__ */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment