[barefoot] Added Newport platform support (#3709)
[barefoot] Added Newport platform support Signed-off-by: Andriy Kokhan <akokhan@barefootnetworks.com>
This commit is contained in:
parent
95466c3ab7
commit
3b51cec9a3
@ -0,0 +1 @@
|
|||||||
|
newport t1
|
@ -0,0 +1 @@
|
|||||||
|
CONSOLE_SPEED=57600
|
@ -0,0 +1,2 @@
|
|||||||
|
{%- set default_topo = 't0' %}
|
||||||
|
{%- include 'buffers_config.j2' %}
|
@ -0,0 +1,71 @@
|
|||||||
|
{% set default_cable = '5m' %}
|
||||||
|
{% set ingress_lossless_pool_size = '4194304' %}
|
||||||
|
{% set ingress_lossy_pool_size = '7340032' %}
|
||||||
|
{% set egress_lossless_pool_size = '16777152' %}
|
||||||
|
{% set egress_lossy_pool_size = '7340032' %}
|
||||||
|
|
||||||
|
{%- macro generate_port_lists(PORT_ALL) %}
|
||||||
|
{# Generate list of ports #}
|
||||||
|
{%- for port_idx in range(0,32) %}
|
||||||
|
{%- if PORT_ALL.append("Ethernet%d" % (port_idx * 4)) %}{%- endif %}
|
||||||
|
{%- endfor %}
|
||||||
|
{%- endmacro %}
|
||||||
|
|
||||||
|
{%- macro generate_buffer_pool_and_profiles() %}
|
||||||
|
"BUFFER_POOL": {
|
||||||
|
"ingress_lossless_pool": {
|
||||||
|
"size": "{{ ingress_lossless_pool_size }}",
|
||||||
|
"type": "ingress",
|
||||||
|
"mode": "dynamic",
|
||||||
|
"xoff": "2867200"
|
||||||
|
},
|
||||||
|
"ingress_lossy_pool": {
|
||||||
|
"size": "{{ ingress_lossy_pool_size }}",
|
||||||
|
"type": "ingress",
|
||||||
|
"mode": "dynamic"
|
||||||
|
},
|
||||||
|
"egress_lossless_pool": {
|
||||||
|
"size": "{{ egress_lossless_pool_size }}",
|
||||||
|
"type": "egress",
|
||||||
|
"mode": "dynamic"
|
||||||
|
},
|
||||||
|
"egress_lossy_pool": {
|
||||||
|
"size": "{{ egress_lossy_pool_size }}",
|
||||||
|
"type": "egress",
|
||||||
|
"mode": "dynamic"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"BUFFER_PROFILE": {
|
||||||
|
"ingress_lossy_profile": {
|
||||||
|
"pool":"[BUFFER_POOL|ingress_lossy_pool]",
|
||||||
|
"size":"4096",
|
||||||
|
"dynamic_th":"3"
|
||||||
|
},
|
||||||
|
"egress_lossless_profile": {
|
||||||
|
"pool":"[BUFFER_POOL|egress_lossless_pool]",
|
||||||
|
"size":"0",
|
||||||
|
"dynamic_th":"7"
|
||||||
|
},
|
||||||
|
"egress_lossy_profile": {
|
||||||
|
"pool":"[BUFFER_POOL|egress_lossy_pool]",
|
||||||
|
"size":"4096",
|
||||||
|
"dynamic_th":"3"
|
||||||
|
},
|
||||||
|
"q_lossy_profile": {
|
||||||
|
"pool":"[BUFFER_POOL|egress_lossy_pool]",
|
||||||
|
"size":"4096",
|
||||||
|
"dynamic_th":"3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{%- endmacro %}
|
||||||
|
|
||||||
|
{%- macro generate_queue_buffers(port_names) %}
|
||||||
|
"BUFFER_QUEUE": {
|
||||||
|
"{{ port_names }}|3-4": {
|
||||||
|
"profile" : "[BUFFER_PROFILE|egress_lossless_profile]"
|
||||||
|
},
|
||||||
|
"{{ port_names }}|0-1": {
|
||||||
|
"profile" : "[BUFFER_PROFILE|q_lossy_profile]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{%- endmacro %}
|
@ -0,0 +1,71 @@
|
|||||||
|
{% set default_cable = '5m' %}
|
||||||
|
{% set ingress_lossless_pool_size = '2097152' %}
|
||||||
|
{% set ingress_lossy_pool_size = '5242880' %}
|
||||||
|
{% set egress_lossless_pool_size = '16777152' %}
|
||||||
|
{% set egress_lossy_pool_size = '5242880' %}
|
||||||
|
|
||||||
|
{%- macro generate_port_lists(PORT_ALL) %}
|
||||||
|
{# Generate list of ports #}
|
||||||
|
{%- for port_idx in range(0,32) %}
|
||||||
|
{%- if PORT_ALL.append("Ethernet%d" % (port_idx * 4)) %}{%- endif %}
|
||||||
|
{%- endfor %}
|
||||||
|
{%- endmacro %}
|
||||||
|
|
||||||
|
{%- macro generate_buffer_pool_and_profiles() %}
|
||||||
|
"BUFFER_POOL": {
|
||||||
|
"ingress_lossless_pool": {
|
||||||
|
"size": "{{ ingress_lossless_pool_size }}",
|
||||||
|
"type": "ingress",
|
||||||
|
"mode": "dynamic",
|
||||||
|
"xoff": "2867200"
|
||||||
|
},
|
||||||
|
"ingress_lossy_pool": {
|
||||||
|
"size": "{{ ingress_lossy_pool_size }}",
|
||||||
|
"type": "ingress",
|
||||||
|
"mode": "dynamic"
|
||||||
|
},
|
||||||
|
"egress_lossless_pool": {
|
||||||
|
"size": "{{ egress_lossless_pool_size }}",
|
||||||
|
"type": "egress",
|
||||||
|
"mode": "dynamic"
|
||||||
|
},
|
||||||
|
"egress_lossy_pool": {
|
||||||
|
"size": "{{ egress_lossy_pool_size }}",
|
||||||
|
"type": "egress",
|
||||||
|
"mode": "dynamic"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"BUFFER_PROFILE": {
|
||||||
|
"ingress_lossy_profile": {
|
||||||
|
"pool":"[BUFFER_POOL|ingress_lossy_pool]",
|
||||||
|
"size":"4096",
|
||||||
|
"dynamic_th":"3"
|
||||||
|
},
|
||||||
|
"egress_lossless_profile": {
|
||||||
|
"pool":"[BUFFER_POOL|egress_lossless_pool]",
|
||||||
|
"size":"0",
|
||||||
|
"dynamic_th":"7"
|
||||||
|
},
|
||||||
|
"egress_lossy_profile": {
|
||||||
|
"pool":"[BUFFER_POOL|egress_lossy_pool]",
|
||||||
|
"size":"4096",
|
||||||
|
"dynamic_th":"3"
|
||||||
|
},
|
||||||
|
"q_lossy_profile": {
|
||||||
|
"pool":"[BUFFER_POOL|egress_lossy_pool]",
|
||||||
|
"size":"4096",
|
||||||
|
"dynamic_th":"3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{%- endmacro %}
|
||||||
|
|
||||||
|
{%- macro generate_queue_buffers(port_names) %}
|
||||||
|
"BUFFER_QUEUE": {
|
||||||
|
"{{ port_names }}|3-4": {
|
||||||
|
"profile" : "[BUFFER_PROFILE|egress_lossless_profile]"
|
||||||
|
},
|
||||||
|
"{{ port_names }}|0-1": {
|
||||||
|
"profile" : "[BUFFER_PROFILE|q_lossy_profile]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{%- endmacro %}
|
@ -0,0 +1,20 @@
|
|||||||
|
# PG lossless profiles.
|
||||||
|
# speed cable size xon xoff threshold
|
||||||
|
10000 5m 34816 18432 16384 7
|
||||||
|
25000 5m 34816 18432 16384 7
|
||||||
|
40000 5m 34816 18432 16384 7
|
||||||
|
50000 5m 34816 18432 16384 7
|
||||||
|
100000 5m 36864 18432 18432 7
|
||||||
|
400000 5m 36864 18432 18432 7
|
||||||
|
10000 40m 36864 18432 18432 7
|
||||||
|
25000 40m 39936 18432 21504 7
|
||||||
|
40000 40m 41984 18432 23552 7
|
||||||
|
50000 40m 41984 18432 23552 7
|
||||||
|
100000 40m 54272 18432 35840 7
|
||||||
|
400000 40m 54272 18432 35840 7
|
||||||
|
10000 300m 49152 18432 30720 7
|
||||||
|
25000 300m 71680 18432 53248 7
|
||||||
|
40000 300m 94208 18432 75776 7
|
||||||
|
50000 300m 94208 18432 75776 7
|
||||||
|
100000 300m 184320 18432 165888 7
|
||||||
|
400000 300m 184320 18432 165888 7
|
@ -0,0 +1,33 @@
|
|||||||
|
# name lanes alias index speed autoneg fec
|
||||||
|
Ethernet0 0,1,2,3,4,5,6,7 Ethernet0 1 400000 0 rs
|
||||||
|
Ethernet8 8,9,10,11,12,13,14,15 Ethernet8 2 400000 0 rs
|
||||||
|
Ethernet16 16,17,18,19,20,21,22,23 Ethernet16 3 400000 0 rs
|
||||||
|
Ethernet24 24,25,26,27,28,29,30,31 Ethernet24 4 400000 0 rs
|
||||||
|
Ethernet32 32,33,34,35,36,37,38,39 Ethernet32 5 400000 0 rs
|
||||||
|
Ethernet40 40,41,42,43,44,45,46,47 Ethernet40 6 400000 0 rs
|
||||||
|
Ethernet48 48,49,50,51,52,53,54,55 Ethernet48 7 400000 0 rs
|
||||||
|
Ethernet56 56,57,58,59,60,61,62,63 Ethernet56 8 400000 0 rs
|
||||||
|
Ethernet64 64,65,66,67,68,69,70,71 Ethernet64 9 400000 0 rs
|
||||||
|
Ethernet72 72,73,74,75,76,77,78,79 Ethernet72 10 400000 0 rs
|
||||||
|
Ethernet80 80,81,82,83,84,85,86,87 Ethernet80 11 400000 0 rs
|
||||||
|
Ethernet88 88,89,90,91,92,93,94,95 Ethernet88 12 400000 0 rs
|
||||||
|
Ethernet96 96,97,98,99,100,101,102,103 Ethernet96 13 400000 0 rs
|
||||||
|
Ethernet104 104,105,106,107,108,109,110,111 Ethernet104 14 400000 0 rs
|
||||||
|
Ethernet112 112,113,114,115,116,117,118,119 Ethernet112 15 400000 0 rs
|
||||||
|
Ethernet120 120,121,122,123,124,125,126,127 Ethernet120 16 400000 0 rs
|
||||||
|
Ethernet128 128,129,130,131,132,133,134,135 Ethernet128 17 400000 0 rs
|
||||||
|
Ethernet136 136,137,138,139,140,141,142,143 Ethernet136 18 400000 0 rs
|
||||||
|
Ethernet144 144,145,146,147,148,149,150,151 Ethernet144 19 400000 0 rs
|
||||||
|
Ethernet152 152,153,154,155,156,157,158,159 Ethernet152 20 400000 0 rs
|
||||||
|
Ethernet160 160,161,162,163,164,165,166,167 Ethernet160 21 400000 0 rs
|
||||||
|
Ethernet168 168,169,170,171,172,173,174,175 Ethernet168 22 400000 0 rs
|
||||||
|
Ethernet176 176,177,178,179,180,181,182,183 Ethernet176 23 400000 0 rs
|
||||||
|
Ethernet184 184,185,186,187,188,189,190,191 Ethernet184 24 400000 0 rs
|
||||||
|
Ethernet192 192,193,194,195,196,197,198,199 Ethernet192 25 400000 0 rs
|
||||||
|
Ethernet200 200,201,202,203,204,205,206,207 Ethernet200 26 400000 0 rs
|
||||||
|
Ethernet208 208,209,210,211,212,213,214,215 Ethernet208 27 400000 0 rs
|
||||||
|
Ethernet216 216,217,218,219,220,221,222,223 Ethernet216 28 400000 0 rs
|
||||||
|
Ethernet224 224,225,226,227,228,229,230,231 Ethernet224 29 400000 0 rs
|
||||||
|
Ethernet232 232,233,234,235,236,237,238,239 Ethernet232 30 400000 0 rs
|
||||||
|
Ethernet240 240,241,242,243,244,245,246,247 Ethernet240 31 400000 0 rs
|
||||||
|
Ethernet248 248,249,250,251,252,253,254,255 Ethernet248 32 400000 0 rs
|
@ -0,0 +1,10 @@
|
|||||||
|
{%- macro generate_tc_to_pg_map() %}
|
||||||
|
"TC_TO_PRIORITY_GROUP_MAP": {
|
||||||
|
"AZURE": {
|
||||||
|
"3": "3",
|
||||||
|
"4": "4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{%- endmacro %}
|
||||||
|
|
||||||
|
{%- include 'qos_config.j2' %}
|
@ -0,0 +1,3 @@
|
|||||||
|
SAI_KEY_WARM_BOOT_WRITE_FILE=/var/warmboot/sai-warmboot.bin
|
||||||
|
SAI_KEY_WARM_BOOT_READ_FILE=/var/warmboot/sai-warmboot.bin
|
||||||
|
|
@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"instance": 0,
|
||||||
|
"chip_list": [
|
||||||
|
{
|
||||||
|
"id": "asic-0",
|
||||||
|
"chip_family": "Tofino2",
|
||||||
|
"instance": 0,
|
||||||
|
"pcie_sysfs_prefix": "/sys/devices/pci0000:00/0000:00:03.0/0000:05:00.0",
|
||||||
|
"pcie_domain": 0,
|
||||||
|
"pcie_bus": 5,
|
||||||
|
"pcie_fn": 0,
|
||||||
|
"pcie_dev": 0,
|
||||||
|
"pcie_int_mode": 1,
|
||||||
|
"sds_fw_path": "share/tofino_sds_fw/avago/firmware"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"p4_devices": [
|
||||||
|
{
|
||||||
|
"device-id": 0,
|
||||||
|
"agent0": "lib/platform/x86_64-accton_as9516bf_32d-r0/libpltfm_mgr.so",
|
||||||
|
"p4_programs": [
|
||||||
|
{
|
||||||
|
"p4_pipelines": [
|
||||||
|
{
|
||||||
|
"p4_pipeline_name": "pipe",
|
||||||
|
"config": "share/switch/pipe/tofino2.bin",
|
||||||
|
"context": "share/switch/pipe/context.json"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"program-name": "switch",
|
||||||
|
"switchsai": "lib/libswitchsai.so",
|
||||||
|
"bfrt-config": "share/switch/bf-rt.json",
|
||||||
|
"model_json_path" : "share/switch/aug_model.json",
|
||||||
|
"switchapi_port_add": false,
|
||||||
|
"non_default_port_ppgs": 5
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
1
device/barefoot/x86_64-accton_as9516bf_32d-r0/plugins
Symbolic link
1
device/barefoot/x86_64-accton_as9516bf_32d-r0/plugins
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../x86_64-accton_wedge100bf_32x-r0/plugins/
|
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"skip_ledd": true,
|
||||||
|
"skip_xcvrd": false,
|
||||||
|
"skip_psud": false,
|
||||||
|
"skip_syseepromd": false
|
||||||
|
}
|
@ -7,6 +7,7 @@ $(SONIC_ONE_IMAGE)_INSTALLS += $(BFN_MODULE) $(PYTHON_THRIFT)
|
|||||||
$(SONIC_ONE_IMAGE)_INSTALLS += $(SYSTEMD_SONIC_GENERATOR)
|
$(SONIC_ONE_IMAGE)_INSTALLS += $(SYSTEMD_SONIC_GENERATOR)
|
||||||
$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(BFN_PLATFORM_MODULE)
|
$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(BFN_PLATFORM_MODULE)
|
||||||
$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(BFN_MONTARA_PLATFORM_MODULE)
|
$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(BFN_MONTARA_PLATFORM_MODULE)
|
||||||
|
$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(BFN_NEWPORT_PLATFORM_MODULE)
|
||||||
$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(WNC_OSW1800_PLATFORM_MODULE)
|
$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(WNC_OSW1800_PLATFORM_MODULE)
|
||||||
$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(INGRASYS_S9180_32X_PLATFORM_MODULE)
|
$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(INGRASYS_S9180_32X_PLATFORM_MODULE)
|
||||||
$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(INGRASYS_S9280_64X_PLATFORM_MODULE)
|
$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(INGRASYS_S9280_64X_PLATFORM_MODULE)
|
||||||
|
13
platform/barefoot/platform-modules-bfn-newport.mk
Normal file
13
platform/barefoot/platform-modules-bfn-newport.mk
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# BFN Platform modules
|
||||||
|
|
||||||
|
BFN_NEWPORT_PLATFORM_MODULE_VERSION = 1.0
|
||||||
|
|
||||||
|
export BFN_NEWPORT_PLATFORM_MODULE_VERSION
|
||||||
|
|
||||||
|
BFN_NEWPORT_PLATFORM_MODULE = sonic-platform-modules-bfn-newport_$(BFN_NEWPORT_PLATFORM_MODULE_VERSION)_amd64.deb
|
||||||
|
$(BFN_NEWPORT_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-bfn-newport
|
||||||
|
$(BFN_NEWPORT_PLATFORM_MODULE)_DEPENDS += $(LINUX_HEADERS) $(LINUX_HEADERS_COMMON)
|
||||||
|
$(BFN_NEWPORT_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as9516bf_32d-r0
|
||||||
|
SONIC_DPKG_DEBS += $(BFN_NEWPORT_PLATFORM_MODULE)
|
||||||
|
|
||||||
|
SONIC_STRETCH_DEBS += $(BFN_NEWPORT_PLATFORM_MODULE)
|
@ -1,6 +1,7 @@
|
|||||||
include $(PLATFORM_PATH)/platform-modules-arista.mk
|
include $(PLATFORM_PATH)/platform-modules-arista.mk
|
||||||
include $(PLATFORM_PATH)/platform-modules-bfn.mk
|
include $(PLATFORM_PATH)/platform-modules-bfn.mk
|
||||||
include $(PLATFORM_PATH)/platform-modules-bfn-montara.mk
|
include $(PLATFORM_PATH)/platform-modules-bfn-montara.mk
|
||||||
|
include $(PLATFORM_PATH)/platform-modules-bfn-newport.mk
|
||||||
include $(PLATFORM_PATH)/platform-modules-wnc-osw1800.mk
|
include $(PLATFORM_PATH)/platform-modules-wnc-osw1800.mk
|
||||||
include $(PLATFORM_PATH)/platform-modules-ingrasys.mk
|
include $(PLATFORM_PATH)/platform-modules-ingrasys.mk
|
||||||
include $(PLATFORM_PATH)/bfn-sai.mk
|
include $(PLATFORM_PATH)/bfn-sai.mk
|
||||||
|
15
platform/barefoot/sonic-platform-modules-bfn-newport/LICENSE
Normal file
15
platform/barefoot/sonic-platform-modules-bfn-newport/LICENSE
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
Copyright (C) 2016 Microsoft, Inc
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
@ -0,0 +1,3 @@
|
|||||||
|
# This file describes the maintainers for sonic-platform-modules-bfn-newport
|
||||||
|
# See the SONiC project governance document for more information
|
||||||
|
Mailinglist = sonicproject@googlegroups.com
|
@ -0,0 +1,2 @@
|
|||||||
|
# sonic-platform-modules-bfn-newport
|
||||||
|
Device drivers for support of BFN platform for the SONiC project
|
@ -0,0 +1,5 @@
|
|||||||
|
# BMC interface
|
||||||
|
auto usb0
|
||||||
|
allow-hotplug usb0
|
||||||
|
iface usb0 inet6
|
||||||
|
up ifconfig usb0 txqueuelen 64
|
@ -0,0 +1,5 @@
|
|||||||
|
sonic-platform-modules-bfn-newport (1.0) unstable; urgency=low
|
||||||
|
|
||||||
|
* Initial release
|
||||||
|
|
||||||
|
-- Support <support@barefootnetworks.com> Mon, 27 Sep 2019 18:00:00 -0800
|
@ -0,0 +1 @@
|
|||||||
|
8
|
@ -0,0 +1,12 @@
|
|||||||
|
Source: sonic-platform-modules-bfn-newport
|
||||||
|
Section: main
|
||||||
|
Priority: extra
|
||||||
|
Maintainer: Support <support@edge-core.com>
|
||||||
|
Build-Depends: debhelper (>= 8.0.0), bzip2
|
||||||
|
Standards-Version: 3.9.3
|
||||||
|
|
||||||
|
Package: sonic-platform-modules-bfn-newport
|
||||||
|
Architecture: amd64
|
||||||
|
Depends: linux-image-4.9.0-9-2-amd64
|
||||||
|
Description: kernel module for bfn platform fpga and scripts for the devices such as fan, led, sfp
|
||||||
|
|
@ -0,0 +1,15 @@
|
|||||||
|
Provides linux kernel driver for BF PCIe devices
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
35
platform/barefoot/sonic-platform-modules-bfn-newport/debian/rules
Executable file
35
platform/barefoot/sonic-platform-modules-bfn-newport/debian/rules
Executable file
@ -0,0 +1,35 @@
|
|||||||
|
#!/usr/bin/make -f
|
||||||
|
|
||||||
|
export INSTALL_MOD_DIR:=extra
|
||||||
|
|
||||||
|
PACKAGE_NAME := sonic-platform-modules-bfn-newport
|
||||||
|
KVERSION ?= $(shell uname -r)
|
||||||
|
KERNEL_SRC := /lib/modules/$(KVERSION)
|
||||||
|
MODULE_SRC := $(shell pwd)/modules
|
||||||
|
SCRIPT_SRC := $(shell pwd)/scripts
|
||||||
|
CONFIGS_SRC := $(shell pwd)/configs
|
||||||
|
|
||||||
|
%:
|
||||||
|
dh $@
|
||||||
|
|
||||||
|
override_dh_auto_build:
|
||||||
|
make -C $(KERNEL_SRC)/build M=$(MODULE_SRC)
|
||||||
|
|
||||||
|
override_dh_auto_install:
|
||||||
|
dh_installdirs -p$(PACKAGE_NAME) $(KERNEL_SRC)/$(INSTALL_MOD_DIR)
|
||||||
|
cp $(MODULE_SRC)/*.ko debian/$(PACKAGE_NAME)/$(KERNEL_SRC)/$(INSTALL_MOD_DIR)
|
||||||
|
dh_installdirs -p$(PACKAGE_NAME) usr/local/bin
|
||||||
|
cp -r $(SCRIPT_SRC)/* debian/$(PACKAGE_NAME)/usr/local/bin
|
||||||
|
dh_installdirs -p$(PACKAGE_NAME) etc/network/interfaces.d/
|
||||||
|
cp -r $(CONFIGS_SRC)/network/interfaces.d/* debian/$(PACKAGE_NAME)/etc/network/interfaces.d/
|
||||||
|
|
||||||
|
override_dh_usrlocal:
|
||||||
|
|
||||||
|
override_dh_pysupport:
|
||||||
|
|
||||||
|
override_dh_clean:
|
||||||
|
dh_clean
|
||||||
|
rm -f $(MODULE_SRC)/*.o $(MODULE_SRC)/*.ko $(MODULE_SRC)/*.mod.c $(MODULE_SRC)/.*.cmd
|
||||||
|
rm -f $(MODULE_SRC)/Module.markers $(MODULE_SRC)/Module.symvers $(MODULE_SRC)/modules.order
|
||||||
|
rm -rf $(MODULE_SRC)/.tmp_versions
|
||||||
|
|
@ -0,0 +1,2 @@
|
|||||||
|
obj-m := bf_fpga.o
|
||||||
|
bf_fpga-y := bf_fpga_main.o bf_fpga_ioctl.o bf_fpga_sysfs.o i2c/bf_fpga_i2c.o i2c/bf_fpga_i2c_ctrl.o i2c/bf_fpga_i2c_porting.o
|
@ -0,0 +1,196 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
Barefoot Networks FPGA Linux driver
|
||||||
|
Copyright(c) 2018 - 2019 Barefoot Networks, Inc.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it
|
||||||
|
under the terms and conditions of the GNU General Public License,
|
||||||
|
version 2, as published by the Free Software Foundation.
|
||||||
|
|
||||||
|
This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
The full GNU General Public License is included in this distribution in
|
||||||
|
the file called "COPYING".
|
||||||
|
|
||||||
|
Contact Information:
|
||||||
|
info@barefootnetworks.com
|
||||||
|
Barefoot Networks, 4750 Patrick Henry Drive, Santa Clara CA 95054
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/dma-mapping.h>
|
||||||
|
#include <linux/cdev.h>
|
||||||
|
#include <linux/ioctl.h>
|
||||||
|
#include <linux/uaccess.h>
|
||||||
|
#include "bf_fpga_priv.h"
|
||||||
|
#include "bf_fpga_ioctl.h"
|
||||||
|
#include "i2c/bf_fpga_i2c.h"
|
||||||
|
|
||||||
|
int bf_fpga_ioctl(struct bf_pci_dev *bfdev,
|
||||||
|
unsigned int cmd,
|
||||||
|
unsigned long arg) {
|
||||||
|
void *addr = (void __user *)arg;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
if (!bfdev || !addr) {
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case BF_FPGA_IOCTL_I2C_CTL: {
|
||||||
|
bf_fpga_i2c_ctl_t i2c_ctl;
|
||||||
|
bool busy;
|
||||||
|
|
||||||
|
if (copy_from_user(&i2c_ctl, addr, sizeof(bf_fpga_i2c_ctl_t))) {
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
switch (i2c_ctl.control_type) {
|
||||||
|
case BF_FPGA_I2C_START:
|
||||||
|
ret = fpga_i2c_start(i2c_ctl.inst_hndl.bus_id);
|
||||||
|
break;
|
||||||
|
case BF_FPGA_I2C_STOP:
|
||||||
|
ret = fpga_i2c_stop(i2c_ctl.inst_hndl.bus_id);
|
||||||
|
break;
|
||||||
|
case BF_FPGA_I2C_RESET:
|
||||||
|
ret = fpga_i2c_reset(i2c_ctl.inst_hndl.bus_id);
|
||||||
|
break;
|
||||||
|
case BF_FPGA_I2C_BUSY:
|
||||||
|
ret = fpga_i2c_is_busy(i2c_ctl.inst_hndl.bus_id, &busy);
|
||||||
|
if (ret == 0) {
|
||||||
|
if (copy_to_user(&(((bf_fpga_i2c_ctl_t *)addr)->is_busy),
|
||||||
|
&busy,
|
||||||
|
sizeof(busy))) {
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BF_FPGA_I2C_INST_EN:
|
||||||
|
ret = fpga_i2c_inst_en(
|
||||||
|
i2c_ctl.inst_hndl.bus_id, i2c_ctl.inst_hndl.inst_id, true);
|
||||||
|
break;
|
||||||
|
case BF_FPGA_I2C_INST_DIS:
|
||||||
|
ret = fpga_i2c_inst_en(
|
||||||
|
i2c_ctl.inst_hndl.bus_id, i2c_ctl.inst_hndl.inst_id, false);
|
||||||
|
break;
|
||||||
|
case BF_FPGA_I2C_INST_PMT:
|
||||||
|
break;
|
||||||
|
case BF_FPGA_I2C_INST_STOP_ON_ERR:
|
||||||
|
break;
|
||||||
|
case BF_FPGA_I2C_INST_INT_EN:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BF_FPGA_IOCTL_I2C_SET_CLK: {
|
||||||
|
bf_fpga_i2c_set_clk_t i2c_clk;
|
||||||
|
if (copy_from_user(&i2c_clk, addr, sizeof(bf_fpga_i2c_set_clk_t))) {
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
ret = fpga_i2c_set_clk(i2c_clk.bus_id, i2c_clk.clock_div);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BF_FPGA_IOCTL_I2C_ONETIME: {
|
||||||
|
bf_fpga_i2c_t i2c_op;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (copy_from_user(&i2c_op, addr, sizeof(bf_fpga_i2c_t))) {
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
ret = fpga_i2c_oneshot(&i2c_op);
|
||||||
|
if (ret == 0) {
|
||||||
|
/* copy read data to user area */
|
||||||
|
for (i = 0; i < i2c_op.num_i2c; i++) {
|
||||||
|
if (i2c_op.i2c_inst[i].rd_cnt) {
|
||||||
|
if (copy_to_user(&(((bf_fpga_i2c_t *)addr)->i2c_inst[i].rd_buf),
|
||||||
|
&i2c_op.i2c_inst[i].rd_buf,
|
||||||
|
i2c_op.i2c_inst[i].rd_cnt)) {
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printk(KERN_ERR
|
||||||
|
"fpga i2c ioctl oneshot bus %d error %d i2c_addr 0x%hhx:0x%hhx "
|
||||||
|
"i2c_status 0x%hhx:0x%hhx\n",
|
||||||
|
i2c_op.inst_hndl.bus_id,
|
||||||
|
ret,
|
||||||
|
i2c_op.i2c_inst[0].i2c_addr,
|
||||||
|
i2c_op.i2c_inst[1].i2c_addr,
|
||||||
|
i2c_op.i2c_inst[0].status,
|
||||||
|
i2c_op.i2c_inst[1].status);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BF_FPGA_IOCTL_I2C_ADD_PR: {
|
||||||
|
bf_fpga_i2c_t i2c_op;
|
||||||
|
if (copy_from_user(&i2c_op, addr, sizeof(bf_fpga_i2c_t))) {
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
ret = fpga_i2c_pr_add(&i2c_op);
|
||||||
|
if (ret == 0) {
|
||||||
|
/* copy read data to user area */
|
||||||
|
if (copy_to_user(&((bf_fpga_i2c_t *)addr)->inst_hndl.inst_id,
|
||||||
|
&i2c_op.inst_hndl.inst_id,
|
||||||
|
sizeof(i2c_op.inst_hndl.inst_id))) {
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printk(KERN_ERR "fpga i2c ioctl add-pr error %d on bus %d\n",
|
||||||
|
ret,
|
||||||
|
i2c_op.inst_hndl.bus_id);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BF_FPGA_IOCTL_I2C_DEL_PR: {
|
||||||
|
bf_fpga_i2c_t i2c_op;
|
||||||
|
if (copy_from_user(&i2c_op, addr, sizeof(bf_fpga_i2c_t))) {
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
ret = fpga_i2c_del(&i2c_op);
|
||||||
|
if (ret != 0) {
|
||||||
|
printk(KERN_ERR "fpga i2c ioctl del-pr error %d on bus %d\n",
|
||||||
|
ret,
|
||||||
|
i2c_op.inst_hndl.bus_id);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BF_FPGA_IOCTL_I2C_RD_DATA: {
|
||||||
|
bf_fpga_i2c_rd_data_t i2c_rd_data;
|
||||||
|
/* get user supplied offset and rd_cnt */
|
||||||
|
if (copy_from_user(
|
||||||
|
&i2c_rd_data, addr, offsetof(bf_fpga_i2c_rd_data_t, rd_buf))) {
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
ret = fpga_i2c_data_read(i2c_rd_data.inst_hndl.bus_id,
|
||||||
|
i2c_rd_data.inst_hndl.inst_id,
|
||||||
|
i2c_rd_data.offset,
|
||||||
|
i2c_rd_data.rd_cnt,
|
||||||
|
i2c_rd_data.rd_buf);
|
||||||
|
if (ret == 0) {
|
||||||
|
if (copy_to_user(&(((bf_fpga_i2c_rd_data_t *)addr)->rd_buf),
|
||||||
|
&i2c_rd_data.rd_buf,
|
||||||
|
i2c_rd_data.rd_cnt)) {
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printk(KERN_ERR "fpga i2c ioctl rd-data error %d on bus %d inst %d\n",
|
||||||
|
ret,
|
||||||
|
i2c_rd_data.inst_hndl.bus_id,
|
||||||
|
i2c_rd_data.inst_hndl.inst_id);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
@ -0,0 +1,131 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
Barefoot Networks FPGA Linux driver
|
||||||
|
Copyright(c) 2018 - 2019 Barefoot Networks, Inc.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it
|
||||||
|
under the terms and conditions of the GNU General Public License,
|
||||||
|
version 2, as published by the Free Software Foundation.
|
||||||
|
|
||||||
|
This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
The full GNU General Public License is included in this distribution in
|
||||||
|
the file called "COPYING".
|
||||||
|
|
||||||
|
Contact Information:
|
||||||
|
info@barefootnetworks.com
|
||||||
|
Barefoot Networks, 4750 Patrick Henry Drive, Santa Clara CA 95054
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
#ifndef _BF_FPGA_IOCTL_H_
|
||||||
|
#define _BF_FPGA_IOCTL_H_
|
||||||
|
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
#include <linux/ioctl.h>
|
||||||
|
#else
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
|
#endif /* __KERNEL__ */
|
||||||
|
|
||||||
|
#define BF_FPGA_IOC_MAGIC 'f'
|
||||||
|
#define BF_I2C_FPGA_NUM_CTRL 34
|
||||||
|
#define BF_FPGA_MAX_I2C_RD_DATA 128
|
||||||
|
#define BF_FPGA_MAX_I2C_WR_DATA 129
|
||||||
|
|
||||||
|
/* i2c control types */
|
||||||
|
#define BF_FPGA_I2C_START 1
|
||||||
|
#define BF_FPGA_I2C_STOP 2
|
||||||
|
#define BF_FPGA_I2C_BUSY 3
|
||||||
|
#define BF_FPGA_I2C_INST_EN 4
|
||||||
|
#define BF_FPGA_I2C_INST_DIS 5
|
||||||
|
#define BF_FPGA_I2C_INST_PMT 6
|
||||||
|
#define BF_FPGA_I2C_INST_STOP_ON_ERR 7
|
||||||
|
#define BF_FPGA_I2C_INST_INT_EN 8
|
||||||
|
#define BF_FPGA_I2C_RESET 9
|
||||||
|
|
||||||
|
/* i2c operation types */
|
||||||
|
#define BF_FPGA_I2C_NOP 0
|
||||||
|
#define BF_FPGA_I2C_WRITE \
|
||||||
|
1 /* <i2c-addr-wr> / <wr-d0> <wr-d1>..[max 129 bytes] */
|
||||||
|
#define BF_FPGA_I2C_READ \
|
||||||
|
2 /* <i2c-addr-rd> / <rd-d0> <rd-d1>..[max 128 bytes] */
|
||||||
|
#define BF_FPGA_I2C_ADDR_READ \
|
||||||
|
3 /* <i2c-addr-wr> / <upto 4 bytes of register offset / <R/S> / \
|
||||||
|
<i2c-addr-rd> <upto 4 bytes of read data> */
|
||||||
|
|
||||||
|
#define FPGA_I2c_ONESHOT_BEGIN_INDEX 0
|
||||||
|
#define FPGA_I2C_ONESHOT_NUM_INST 15
|
||||||
|
#define FPGA_I2C_PERIODIC_BEGIN_INDEX (FPGA_I2C_ONESHOT_NUM_INST)
|
||||||
|
#define FPGA_I2C_PERIODIC_NUM_INST 16
|
||||||
|
#define FPGA_I2C_NUM_INST \
|
||||||
|
(FPGA_I2C_ONESHOT_NUM_INST + FPGA_I2C_PERIODIC_NUM_INST)
|
||||||
|
/* maximum i2c instructions that can be handled in one system call */
|
||||||
|
#define BF_FPGA_I2C_MAX_NUM_INST 3
|
||||||
|
|
||||||
|
typedef struct bf_fpga_i2c_set_clk_s {
|
||||||
|
/* 0:100k, 1:400k, 2:1M, or: 125e6/<desired freq>/3 */
|
||||||
|
int clock_div; /* clock divider */
|
||||||
|
unsigned char bus_id; /* controller index */
|
||||||
|
} bf_fpga_i2c_set_clk_t;
|
||||||
|
|
||||||
|
typedef struct bf_fpga_inst_hndl_s {
|
||||||
|
int inst_id; /* instruction index within the controller memory space */
|
||||||
|
unsigned char bus_id; /* controller index */
|
||||||
|
unsigned char status;
|
||||||
|
} bf_fpga_inst_hndl_t;
|
||||||
|
|
||||||
|
typedef struct bf_fpga_i2c_inst_s {
|
||||||
|
bool preemt;
|
||||||
|
bool en;
|
||||||
|
unsigned char i2c_addr; /* i2c device address in 7 bit format */
|
||||||
|
unsigned char i2c_type; /* type of i2c cycle */
|
||||||
|
unsigned char delay; /* delay in TBD - microseconds before i2c transaction */
|
||||||
|
unsigned char ctrl;
|
||||||
|
unsigned char wr_cnt; /* number of bytes to write (after i2c address) */
|
||||||
|
unsigned char rd_cnt; /* number of bytes to read */
|
||||||
|
union {
|
||||||
|
unsigned char
|
||||||
|
wr_buf[BF_FPGA_MAX_I2C_WR_DATA]; /* write data source buffer */
|
||||||
|
unsigned char rd_buf[BF_FPGA_MAX_I2C_RD_DATA]; /* read data dest buffer */
|
||||||
|
};
|
||||||
|
unsigned char status;
|
||||||
|
unsigned char retry_cnt; /* if fpga maintains retry count */
|
||||||
|
unsigned char mux; /* if fpga maintains internal MUX */
|
||||||
|
} bf_fpga_i2c_inst_t;
|
||||||
|
|
||||||
|
typedef struct bf_fpga_i2c_s {
|
||||||
|
unsigned char num_i2c; /* number of i2c operations */
|
||||||
|
unsigned char one_time; /* one time or periodic */
|
||||||
|
bf_fpga_inst_hndl_t inst_hndl;
|
||||||
|
bf_fpga_i2c_inst_t i2c_inst[BF_FPGA_I2C_MAX_NUM_INST];
|
||||||
|
} bf_fpga_i2c_t;
|
||||||
|
|
||||||
|
typedef struct bf_fpga_i2c_rd_data_s {
|
||||||
|
bf_fpga_inst_hndl_t inst_hndl;
|
||||||
|
unsigned char offset;
|
||||||
|
unsigned char rd_cnt;
|
||||||
|
unsigned char rd_buf[BF_FPGA_MAX_I2C_RD_DATA];
|
||||||
|
} bf_fpga_i2c_rd_data_t;
|
||||||
|
|
||||||
|
typedef struct bf_fpga_i2c_ctl_s {
|
||||||
|
bf_fpga_inst_hndl_t inst_hndl;
|
||||||
|
unsigned char control_type; /* start, stop, reset, enable, disable or busy */
|
||||||
|
bool is_busy;
|
||||||
|
} bf_fpga_i2c_ctl_t;
|
||||||
|
|
||||||
|
#define BF_FPGA_IOCTL_I2C_CTL _IOWR(BF_FPGA_IOC_MAGIC, 0, bf_fpga_i2c_ctl_t)
|
||||||
|
#define BF_FPGA_IOCTL_I2C_ONETIME _IOWR(BF_FPGA_IOC_MAGIC, 1, bf_fpga_i2c_t)
|
||||||
|
#define BF_FPGA_IOCTL_I2C_ADD_PR _IOWR(BF_FPGA_IOC_MAGIC, 2, bf_fpga_i2c_t)
|
||||||
|
#define BF_FPGA_IOCTL_I2C_DEL_PR _IOWR(BF_FPGA_IOC_MAGIC, 3, bf_fpga_i2c_t)
|
||||||
|
#define BF_FPGA_IOCTL_I2C_RD_DATA \
|
||||||
|
_IOWR(BF_FPGA_IOC_MAGIC, 4, bf_fpga_i2c_rd_data_t)
|
||||||
|
#define BF_FPGA_IOCTL_I2C_SET_CLK \
|
||||||
|
_IOW(BF_FPGA_IOC_MAGIC, 5, bf_fpga_i2c_set_clk_t)
|
||||||
|
|
||||||
|
#endif /* _BF_FPGA_IOCTL_H_ */
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,141 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
Barefoot Networks FPGA Linux driver
|
||||||
|
Copyright(c) 2018 - 2019 Barefoot Networks, Inc.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it
|
||||||
|
under the terms and conditions of the GNU General Public License,
|
||||||
|
version 2, as published by the Free Software Foundation.
|
||||||
|
|
||||||
|
This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
The full GNU General Public License is included in this distribution in
|
||||||
|
the file called "COPYING".
|
||||||
|
|
||||||
|
Contact Information:
|
||||||
|
info@barefootnetworks.com
|
||||||
|
Barefoot Networks, 4750 Patrick Henry Drive, Santa Clara CA 95054
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
#ifndef _BF_FPGA_H_
|
||||||
|
#define _BF_FPGA_H_
|
||||||
|
|
||||||
|
#define PCI_VENDOR_ID_BF 0x1d1c
|
||||||
|
#define BF_FPGA_DEV_ID_JBAY_0 0x01F0
|
||||||
|
|
||||||
|
#ifndef PCI_MSIX_ENTRY_SIZE
|
||||||
|
#define PCI_MSIX_ENTRY_SIZE 16
|
||||||
|
#define PCI_MSIX_ENTRY_LOWER_ADDR 0
|
||||||
|
#define PCI_MSIX_ENTRY_UPPER_ADDR 4
|
||||||
|
#define PCI_MSIX_ENTRY_DATA 8
|
||||||
|
#define PCI_MSIX_ENTRY_VECTOR_CTRL 12
|
||||||
|
#define PCI_MSIX_ENTRY_CTRL_MASKBIT 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define BF_CLASS_NAME "bf_fpga"
|
||||||
|
#define BF_FPGA_MAX_DEVICE_CNT 1
|
||||||
|
#define BF_INTR_MODE_NONE_NAME "none"
|
||||||
|
#define BF_INTR_MODE_LEGACY_NAME "legacy"
|
||||||
|
#define BF_INTR_MODE_MSI_NAME "msi"
|
||||||
|
#define BF_INTR_MODE_MSIX_NAME "msix"
|
||||||
|
#define BF_MAX_BAR_MAPS 6
|
||||||
|
#define BF_MSIX_ENTRY_CNT 1
|
||||||
|
#define BF_MSI_ENTRY_CNT 1
|
||||||
|
|
||||||
|
/* sysfs codes */
|
||||||
|
#define BF_SYSFS_NEW_DEVICE 1
|
||||||
|
#define BF_SYSFS_RM_DEVICE 0
|
||||||
|
#define BF_SYSFS_I2C_START 2
|
||||||
|
|
||||||
|
/* interrupt mode */
|
||||||
|
enum bf_intr_mode {
|
||||||
|
BF_INTR_MODE_NONE = 0,
|
||||||
|
BF_INTR_MODE_LEGACY,
|
||||||
|
BF_INTR_MODE_MSI,
|
||||||
|
BF_INTR_MODE_MSIX
|
||||||
|
};
|
||||||
|
|
||||||
|
/* device memory */
|
||||||
|
struct bf_dev_mem {
|
||||||
|
const char *name;
|
||||||
|
phys_addr_t addr;
|
||||||
|
resource_size_t size;
|
||||||
|
void __iomem *internal_addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bf_listener {
|
||||||
|
struct bf_pci_dev *bfdev;
|
||||||
|
s32 event_count[BF_MSIX_ENTRY_CNT];
|
||||||
|
int minor;
|
||||||
|
struct bf_listener *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* device information */
|
||||||
|
struct bf_dev_info {
|
||||||
|
struct module *owner;
|
||||||
|
struct device *dev;
|
||||||
|
int minor;
|
||||||
|
atomic_t event[BF_MSIX_ENTRY_CNT];
|
||||||
|
wait_queue_head_t wait;
|
||||||
|
const char *version;
|
||||||
|
struct bf_dev_mem mem[BF_MAX_BAR_MAPS];
|
||||||
|
struct msix_entry *msix_entries;
|
||||||
|
long irq; /* first irq vector */
|
||||||
|
int num_irq; /* number of irq vectors */
|
||||||
|
unsigned long irq_flags; /* sharable ?? */
|
||||||
|
int pci_error_state; /* was there a pci bus error */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* cookie to be passed to IRQ handler, useful especially with MSIX */
|
||||||
|
struct bf_int_vector {
|
||||||
|
struct bf_pci_dev *bf_dev;
|
||||||
|
int int_vec_offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* sysfs related structs */
|
||||||
|
#define BF_FPGA_SYSFS_CNT 64
|
||||||
|
#define BF_FPGA_SYSFS_NAME_SIZE 32
|
||||||
|
|
||||||
|
struct bf_fpga_sysfs_buff {
|
||||||
|
struct device_attribute dev_attr;
|
||||||
|
char name[BF_FPGA_SYSFS_NAME_SIZE];
|
||||||
|
int bus_id;
|
||||||
|
unsigned char i2c_addr;
|
||||||
|
size_t i2c_rd_size; /* bytes to read from the device */
|
||||||
|
int sysfs_code; /* unique code for each sysfs file */
|
||||||
|
struct bf_pci_dev *fpgadev; /* back pointer */
|
||||||
|
bool in_use;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* structure describing the private information for a BF pcie device.
|
||||||
|
*/
|
||||||
|
struct bf_pci_dev {
|
||||||
|
struct bf_dev_info info;
|
||||||
|
struct pci_dev *pdev;
|
||||||
|
enum bf_intr_mode mode;
|
||||||
|
u8 instance;
|
||||||
|
char name[16];
|
||||||
|
struct bf_int_vector bf_int_vec[BF_MSIX_ENTRY_CNT];
|
||||||
|
struct bf_listener *
|
||||||
|
listener_head; /* head of a singly linked list of listeners */
|
||||||
|
struct bf_fpga_sysfs_buff fpga_sysfs_buff[BF_FPGA_SYSFS_CNT];
|
||||||
|
struct bf_fpga_sysfs_buff fpga_sysfs_new_device;
|
||||||
|
struct bf_fpga_sysfs_buff fpga_sysfs_rm_device;
|
||||||
|
struct bf_fpga_sysfs_buff fpga_sysfs_st_i2c;
|
||||||
|
spinlock_t sysfs_slock;
|
||||||
|
};
|
||||||
|
|
||||||
|
int bf_fpga_ioctl(struct bf_pci_dev *bfdev,
|
||||||
|
unsigned int cmd,
|
||||||
|
unsigned long arg);
|
||||||
|
int bf_fpga_sysfs_add(struct bf_pci_dev *fpgadev);
|
||||||
|
void bf_fpga_sysfs_del(struct bf_pci_dev *fpgadev);
|
||||||
|
|
||||||
|
#endif /* _BF_FPGA_H_ */
|
@ -0,0 +1,335 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
Barefoot Networks FPGA Linux driver
|
||||||
|
Copyright(c) 2018 - 2019 Barefoot Networks, Inc.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it
|
||||||
|
under the terms and conditions of the GNU General Public License,
|
||||||
|
version 2, as published by the Free Software Foundation.
|
||||||
|
|
||||||
|
This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
The full GNU General Public License is included in this distribution in
|
||||||
|
the file called "COPYING".
|
||||||
|
|
||||||
|
Contact Information:
|
||||||
|
info@barefootnetworks.com
|
||||||
|
Barefoot Networks, 4750 Patrick Henry Drive, Santa Clara CA 95054
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/dma-mapping.h>
|
||||||
|
#include <linux/cdev.h>
|
||||||
|
#include <linux/pci.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
#include "bf_fpga_priv.h"
|
||||||
|
#include "bf_fpga_ioctl.h"
|
||||||
|
#include "i2c/bf_fpga_i2c.h"
|
||||||
|
|
||||||
|
/* reads 1 byte from the i2c device */
|
||||||
|
static ssize_t bf_fpga_sysfs_i2c_get(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
char *buf) {
|
||||||
|
bf_fpga_i2c_t i2c_op;
|
||||||
|
ssize_t size, cur_size;
|
||||||
|
struct bf_fpga_sysfs_buff *sysfs_buf =
|
||||||
|
container_of(attr, struct bf_fpga_sysfs_buff, dev_attr);
|
||||||
|
|
||||||
|
if (!sysfs_buf) {
|
||||||
|
printk(KERN_ERR "fpga-i2c bad attr pointer in sysfs_read\n");
|
||||||
|
return -ENXIO; /* something not quite right here; but, don't panic */
|
||||||
|
}
|
||||||
|
i2c_op.num_i2c = 1;
|
||||||
|
i2c_op.one_time = 1;
|
||||||
|
i2c_op.inst_hndl.bus_id = sysfs_buf->bus_id;
|
||||||
|
i2c_op.i2c_inst[0].preemt = false;
|
||||||
|
i2c_op.i2c_inst[0].en = true;
|
||||||
|
i2c_op.i2c_inst[0].i2c_addr = sysfs_buf->i2c_addr;
|
||||||
|
i2c_op.i2c_inst[0].i2c_type = BF_FPGA_I2C_READ;
|
||||||
|
i2c_op.i2c_inst[0].delay = 0;
|
||||||
|
i2c_op.i2c_inst[0].wr_cnt = 0;
|
||||||
|
cur_size = sysfs_buf->i2c_rd_size;
|
||||||
|
/* limit to PAGE_SIZE per the sysfs contract */
|
||||||
|
if (cur_size >= PAGE_SIZE) {
|
||||||
|
cur_size = PAGE_SIZE;
|
||||||
|
}
|
||||||
|
size = 0;
|
||||||
|
while (cur_size > 0) {
|
||||||
|
unsigned char cur_cnt;
|
||||||
|
if (cur_size > 64) {
|
||||||
|
cur_cnt = 64;
|
||||||
|
} else {
|
||||||
|
cur_cnt = (unsigned char)cur_size;
|
||||||
|
}
|
||||||
|
i2c_op.i2c_inst[0].rd_cnt = cur_cnt;
|
||||||
|
if (fpga_i2c_oneshot(&i2c_op)) {
|
||||||
|
printk(KERN_ERR
|
||||||
|
"fpga-i2c read one-shot error bus %d addr 0x%hhx status 0x%hhx\n",
|
||||||
|
i2c_op.inst_hndl.bus_id,
|
||||||
|
i2c_op.i2c_inst[0].i2c_addr,
|
||||||
|
i2c_op.i2c_inst[0].status);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
memcpy(buf, i2c_op.i2c_inst[0].rd_buf, cur_cnt);
|
||||||
|
buf += cur_cnt;
|
||||||
|
size += cur_cnt;
|
||||||
|
cur_size -= cur_cnt;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write the number of bytes supplied to the i2c device, 1st byte has to be
|
||||||
|
the count(max 8) */
|
||||||
|
static ssize_t bf_fpga_sysfs_i2c_set(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
const char *buf,
|
||||||
|
size_t count) {
|
||||||
|
bf_fpga_i2c_t i2c_op;
|
||||||
|
size_t size, cur_cnt;
|
||||||
|
struct bf_fpga_sysfs_buff *sysfs_buf =
|
||||||
|
container_of(attr, struct bf_fpga_sysfs_buff, dev_attr);
|
||||||
|
|
||||||
|
if (!sysfs_buf || (count == 0)) {
|
||||||
|
printk(KERN_ERR "fpga-i2c bad attr pointer in sysfs_write\n");
|
||||||
|
return -ENXIO; /* something not quite right here; but, don't panic */
|
||||||
|
}
|
||||||
|
size = 0;
|
||||||
|
while (count > 0) {
|
||||||
|
if (count > 64) {
|
||||||
|
cur_cnt = 64;
|
||||||
|
} else {
|
||||||
|
cur_cnt = count;
|
||||||
|
}
|
||||||
|
i2c_op.i2c_inst[0].wr_cnt = cur_cnt;
|
||||||
|
i2c_op.i2c_inst[0].rd_cnt = 0;
|
||||||
|
memcpy(i2c_op.i2c_inst[0].wr_buf, buf, cur_cnt);
|
||||||
|
i2c_op.num_i2c = 1;
|
||||||
|
i2c_op.one_time = 1;
|
||||||
|
i2c_op.inst_hndl.bus_id = sysfs_buf->bus_id;
|
||||||
|
i2c_op.i2c_inst[0].preemt = false;
|
||||||
|
i2c_op.i2c_inst[0].en = true;
|
||||||
|
i2c_op.i2c_inst[0].i2c_addr = sysfs_buf->i2c_addr;
|
||||||
|
i2c_op.i2c_inst[0].i2c_type = BF_FPGA_I2C_WRITE;
|
||||||
|
i2c_op.i2c_inst[0].delay = 0;
|
||||||
|
if (fpga_i2c_oneshot(&i2c_op)) {
|
||||||
|
printk(
|
||||||
|
KERN_ERR
|
||||||
|
"fpga-i2c write one-shot error bus %d addr 0x%hhx status 0x%hhx\n",
|
||||||
|
i2c_op.inst_hndl.bus_id,
|
||||||
|
i2c_op.i2c_inst[0].i2c_addr,
|
||||||
|
i2c_op.i2c_inst[0].status);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
buf += cur_cnt;
|
||||||
|
size += cur_cnt;
|
||||||
|
count -= cur_cnt;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int find_matching_sysfs_buf(struct bf_pci_dev *fpgadev,
|
||||||
|
int bus_id,
|
||||||
|
unsigned char i2c_addr) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* check if a sysfs entry already exists */
|
||||||
|
for (i = 0; i < BF_FPGA_SYSFS_CNT; i++) {
|
||||||
|
if (fpgadev->fpga_sysfs_buff[i].bus_id == bus_id &&
|
||||||
|
fpgadev->fpga_sysfs_buff[i].i2c_addr == i2c_addr) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* could not find a matching sysfs buffer */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t bf_fpga_sysfs_fixed_get(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
char *buf) {
|
||||||
|
(void)dev;
|
||||||
|
(void)attr;
|
||||||
|
(void)buf;
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t bf_fpga_sysfs_fixed_set(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
const char *buf,
|
||||||
|
size_t count) {
|
||||||
|
struct bf_pci_dev *fpgadev;
|
||||||
|
int i, en, bus_id, ret, rd_size;
|
||||||
|
char fname[BF_FPGA_SYSFS_NAME_SIZE];
|
||||||
|
unsigned char i2c_addr;
|
||||||
|
struct bf_fpga_sysfs_buff *new_buf;
|
||||||
|
struct bf_fpga_sysfs_buff *sysfs_buf =
|
||||||
|
container_of(attr, struct bf_fpga_sysfs_buff, dev_attr);
|
||||||
|
|
||||||
|
if (!sysfs_buf || (count == 0)) {
|
||||||
|
printk(KERN_ERR "fpga i2c bad attr pointer in fixed_sysfs_write\n");
|
||||||
|
return -ENXIO; /* something not quite right here; but, don't panic */
|
||||||
|
}
|
||||||
|
fpgadev = sysfs_buf->fpgadev;
|
||||||
|
|
||||||
|
switch (sysfs_buf->sysfs_code) {
|
||||||
|
case BF_SYSFS_NEW_DEVICE: /* new_device request */
|
||||||
|
ret = sscanf(buf, "%s %d %hhx %d", fname, &bus_id, &i2c_addr, &rd_size);
|
||||||
|
/* default rd_size to 1 if not supplied or invalid */
|
||||||
|
if (ret < 3) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
if (ret < 4 || rd_size > PAGE_SIZE) {
|
||||||
|
rd_size = 1;
|
||||||
|
}
|
||||||
|
if (bus_id >= BF_I2C_FPGA_NUM_CTRL || i2c_addr >= 0x80) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
/* find out the free sysfs_buffer to use */
|
||||||
|
spin_lock(&fpgadev->sysfs_slock);
|
||||||
|
if (find_matching_sysfs_buf(fpgadev, bus_id, i2c_addr) != -1) {
|
||||||
|
/* there is already an matching entry */
|
||||||
|
spin_unlock(&fpgadev->sysfs_slock);
|
||||||
|
return -ENOSPC;
|
||||||
|
}
|
||||||
|
for (i = 0; i < BF_FPGA_SYSFS_CNT; i++) {
|
||||||
|
if (!fpgadev->fpga_sysfs_buff[i].in_use) {
|
||||||
|
fpgadev->fpga_sysfs_buff[i].in_use = true;
|
||||||
|
new_buf = &fpgadev->fpga_sysfs_buff[i];
|
||||||
|
new_buf->i2c_addr = i2c_addr;
|
||||||
|
new_buf->i2c_rd_size = (size_t)rd_size;
|
||||||
|
new_buf->bus_id = bus_id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spin_unlock(&fpgadev->sysfs_slock);
|
||||||
|
if (i >= BF_FPGA_SYSFS_CNT) {
|
||||||
|
/* no free buffer available, return with ERROR */
|
||||||
|
return -ENOSPC;
|
||||||
|
}
|
||||||
|
/* create a new sysfs entry now */
|
||||||
|
new_buf->dev_attr.show = bf_fpga_sysfs_i2c_get;
|
||||||
|
new_buf->dev_attr.store = bf_fpga_sysfs_i2c_set;
|
||||||
|
new_buf->fpgadev = fpgadev;
|
||||||
|
new_buf->dev_attr.attr.mode = S_IWUSR | S_IRUGO;
|
||||||
|
new_buf->sysfs_code = 0;
|
||||||
|
snprintf(new_buf->name, BF_FPGA_SYSFS_NAME_SIZE, "%s", fname);
|
||||||
|
new_buf->dev_attr.attr.name = new_buf->name;
|
||||||
|
ret = device_create_file(&(fpgadev->pdev->dev), &new_buf->dev_attr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BF_SYSFS_RM_DEVICE: /* remove device request */
|
||||||
|
ret = sscanf(buf, "%d %hhx", &bus_id, &i2c_addr);
|
||||||
|
if (ret < 2) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
if (bus_id >= BF_I2C_FPGA_NUM_CTRL || i2c_addr >= 0x80) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
/* delete the sysfs file corresponding to the i2c address */
|
||||||
|
spin_lock(&fpgadev->sysfs_slock);
|
||||||
|
i = find_matching_sysfs_buf(fpgadev, bus_id, i2c_addr);
|
||||||
|
if (i == -1) {
|
||||||
|
/* there is no matching entry */
|
||||||
|
spin_unlock(&fpgadev->sysfs_slock);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
/* must invalidate bus_id and i2c_addr when marking the buffer
|
||||||
|
* not-in-use
|
||||||
|
*/
|
||||||
|
new_buf = &fpgadev->fpga_sysfs_buff[i];
|
||||||
|
new_buf->i2c_addr = 0xff;
|
||||||
|
new_buf->bus_id = -1;
|
||||||
|
fpgadev->fpga_sysfs_buff[i].in_use = false;
|
||||||
|
spin_unlock(&fpgadev->sysfs_slock);
|
||||||
|
device_remove_file(&fpgadev->pdev->dev, &new_buf->dev_attr);
|
||||||
|
new_buf->name[0] = 0; /* nullify the name */
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BF_SYSFS_I2C_START: /* start-stop i2c request */
|
||||||
|
ret = sscanf(buf, "%d %d", &bus_id, &en);
|
||||||
|
if (ret < 2) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
if (bus_id >= BF_I2C_FPGA_NUM_CTRL) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
if (en) {
|
||||||
|
ret = fpga_i2c_start(bus_id);
|
||||||
|
} else {
|
||||||
|
ret = fpga_i2c_stop(bus_id);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret = -EINVAL;
|
||||||
|
}
|
||||||
|
return ((ret == 0) ? count : ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
int bf_fpga_sysfs_add(struct bf_pci_dev *fpgadev) {
|
||||||
|
int rc = 0;
|
||||||
|
u8 *name;
|
||||||
|
|
||||||
|
spin_lock_init(&fpgadev->sysfs_slock);
|
||||||
|
/* Add two sysfs files statically, new_device and remove_device.
|
||||||
|
* Handlers of these two fles can dynamically add more sysfs
|
||||||
|
* files (or remove files) based on the platform.
|
||||||
|
*/
|
||||||
|
fpgadev->fpga_sysfs_new_device.dev_attr.show = bf_fpga_sysfs_fixed_get;
|
||||||
|
fpgadev->fpga_sysfs_new_device.dev_attr.store = bf_fpga_sysfs_fixed_set;
|
||||||
|
fpgadev->fpga_sysfs_new_device.fpgadev = fpgadev;
|
||||||
|
fpgadev->fpga_sysfs_new_device.dev_attr.attr.mode = S_IWUSR | S_IRUGO;
|
||||||
|
fpgadev->fpga_sysfs_new_device.sysfs_code = BF_SYSFS_NEW_DEVICE;
|
||||||
|
name = fpgadev->fpga_sysfs_new_device.name;
|
||||||
|
snprintf(name, BF_FPGA_SYSFS_NAME_SIZE, "new_device");
|
||||||
|
fpgadev->fpga_sysfs_new_device.dev_attr.attr.name = name;
|
||||||
|
rc |= device_create_file(&(fpgadev->pdev->dev),
|
||||||
|
&fpgadev->fpga_sysfs_new_device.dev_attr);
|
||||||
|
|
||||||
|
fpgadev->fpga_sysfs_rm_device.dev_attr.show = bf_fpga_sysfs_fixed_get;
|
||||||
|
fpgadev->fpga_sysfs_rm_device.dev_attr.store = bf_fpga_sysfs_fixed_set;
|
||||||
|
fpgadev->fpga_sysfs_rm_device.fpgadev = fpgadev;
|
||||||
|
fpgadev->fpga_sysfs_rm_device.dev_attr.attr.mode = S_IWUSR | S_IRUGO;
|
||||||
|
fpgadev->fpga_sysfs_rm_device.sysfs_code = BF_SYSFS_RM_DEVICE;
|
||||||
|
name = fpgadev->fpga_sysfs_rm_device.name;
|
||||||
|
snprintf(name, BF_FPGA_SYSFS_NAME_SIZE, "remove_device");
|
||||||
|
fpgadev->fpga_sysfs_rm_device.dev_attr.attr.name = name;
|
||||||
|
rc |= device_create_file(&(fpgadev->pdev->dev),
|
||||||
|
&fpgadev->fpga_sysfs_rm_device.dev_attr);
|
||||||
|
|
||||||
|
/* sysfs for i2c start-stop control */
|
||||||
|
fpgadev->fpga_sysfs_st_i2c.dev_attr.show = bf_fpga_sysfs_fixed_get;
|
||||||
|
fpgadev->fpga_sysfs_st_i2c.dev_attr.store = bf_fpga_sysfs_fixed_set;
|
||||||
|
fpgadev->fpga_sysfs_st_i2c.fpgadev = fpgadev;
|
||||||
|
fpgadev->fpga_sysfs_st_i2c.dev_attr.attr.mode = S_IWUSR | S_IRUGO;
|
||||||
|
fpgadev->fpga_sysfs_st_i2c.sysfs_code = BF_SYSFS_I2C_START;
|
||||||
|
name = fpgadev->fpga_sysfs_st_i2c.name;
|
||||||
|
snprintf(name, BF_FPGA_SYSFS_NAME_SIZE, "i2c_start");
|
||||||
|
fpgadev->fpga_sysfs_st_i2c.dev_attr.attr.name = name;
|
||||||
|
rc |= device_create_file(&(fpgadev->pdev->dev),
|
||||||
|
&fpgadev->fpga_sysfs_st_i2c.dev_attr);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bf_fpga_sysfs_del(struct bf_pci_dev *fpgadev) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
device_remove_file(&fpgadev->pdev->dev,
|
||||||
|
&fpgadev->fpga_sysfs_new_device.dev_attr);
|
||||||
|
device_remove_file(&fpgadev->pdev->dev,
|
||||||
|
&fpgadev->fpga_sysfs_rm_device.dev_attr);
|
||||||
|
device_remove_file(&fpgadev->pdev->dev, &fpgadev->fpga_sysfs_st_i2c.dev_attr);
|
||||||
|
for (i = 0; i < BF_FPGA_SYSFS_CNT; i++) {
|
||||||
|
if (fpgadev->fpga_sysfs_buff[i].in_use) {
|
||||||
|
device_remove_file(&fpgadev->pdev->dev,
|
||||||
|
&fpgadev->fpga_sysfs_buff[i].dev_attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,516 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
Barefoot Networks FPGA Linux driver
|
||||||
|
Copyright(c) 2018 - 2019 Barefoot Networks, Inc.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it
|
||||||
|
under the terms and conditions of the GNU General Public License,
|
||||||
|
version 2, as published by the Free Software Foundation.
|
||||||
|
|
||||||
|
This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
The full GNU General Public License is included in this distribution in
|
||||||
|
the file called "COPYING".
|
||||||
|
|
||||||
|
Contact Information:
|
||||||
|
info@barefootnetworks.com
|
||||||
|
Barefoot Networks, 4750 Patrick Henry Drive, Santa Clara CA 95054
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include "bf_fpga_i2c_priv_porting.h"
|
||||||
|
#include <bf_fpga_ioctl.h>
|
||||||
|
#include "bf_fpga_i2c_priv.h"
|
||||||
|
#include "bf_fpga_i2c.h"
|
||||||
|
#include "bf_fpga_i2c_reg.h"
|
||||||
|
|
||||||
|
/* allocate find physically contiguous free blocks of instructions in one time
|
||||||
|
* or periodic area and mark them "in-use" */
|
||||||
|
static int get_next_free_index(fpga_i2c_controller_t *i2c_ctrl,
|
||||||
|
int cnt,
|
||||||
|
bool pr) {
|
||||||
|
int i, j, begin, end;
|
||||||
|
|
||||||
|
if (pr) {
|
||||||
|
begin = FPGA_I2C_PERIODIC_BEGIN_INDEX;
|
||||||
|
end = FPGA_I2C_NUM_INST;
|
||||||
|
} else {
|
||||||
|
begin = FPGA_I2c_ONESHOT_BEGIN_INDEX;
|
||||||
|
end = FPGA_I2C_ONESHOT_NUM_INST;
|
||||||
|
}
|
||||||
|
|
||||||
|
bf_fpga_fast_lock(&i2c_ctrl->spinlock);
|
||||||
|
for (i = begin; i < end;) {
|
||||||
|
/* check if there are cnt number of free slots here */
|
||||||
|
for (j = 0; j < cnt; j++) {
|
||||||
|
if (i2c_ctrl->i2c_inst[i + j].in_use) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (j == cnt) {
|
||||||
|
/* we found enough free slots, so, return i */
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
/* we did not find enough free slots, continue searching */
|
||||||
|
i += (j + 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i < end) {
|
||||||
|
for (j = 0; j < cnt; j++) {
|
||||||
|
i2c_ctrl->i2c_inst[i + j].in_use = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
i = -1;
|
||||||
|
}
|
||||||
|
bf_fpga_fast_unlock(&i2c_ctrl->spinlock);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* free physically contiguous in-use blocks of instructions */
|
||||||
|
static void release_index(fpga_i2c_controller_t *i2c_ctrl,
|
||||||
|
int inst_id,
|
||||||
|
int cnt) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (inst_id < 0 || (inst_id + cnt) >= FPGA_I2C_NUM_INST) {
|
||||||
|
return; /* invalid id */
|
||||||
|
}
|
||||||
|
bf_fpga_fast_lock(&i2c_ctrl->spinlock);
|
||||||
|
for (i = inst_id; i < (inst_id + cnt); i++) {
|
||||||
|
i2c_ctrl->i2c_inst[i].in_use = false;
|
||||||
|
}
|
||||||
|
bf_fpga_fast_unlock(&i2c_ctrl->spinlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* convert miroseconds to i2c-instruction delay parameter */
|
||||||
|
static int us_to_fpga_delay(int microsec) {
|
||||||
|
int delay;
|
||||||
|
|
||||||
|
if (microsec < 10) {
|
||||||
|
delay = 0;
|
||||||
|
} else if (microsec < 100) {
|
||||||
|
delay = 1;
|
||||||
|
} else if (microsec < 1000) {
|
||||||
|
delay = 2;
|
||||||
|
} else if (microsec < 10000) {
|
||||||
|
delay = 3;
|
||||||
|
} else if (microsec < 100000) {
|
||||||
|
delay = 4;
|
||||||
|
} else if (microsec < 1000000) {
|
||||||
|
delay = 5;
|
||||||
|
} else {
|
||||||
|
delay = 6;
|
||||||
|
}
|
||||||
|
return delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* populate single i2c_instruction at the given instruction slot */
|
||||||
|
static int fpga_i2c_enqueue(int bus_id,
|
||||||
|
int inst_id,
|
||||||
|
bf_fpga_i2c_inst_t *i2c_inst) {
|
||||||
|
fpga_i2c_controller_t *i2c_ctrl = fpga_i2c_ctrl_get(bus_id);
|
||||||
|
int delay = us_to_fpga_delay(i2c_inst->delay);
|
||||||
|
uint32_t wd0 = 0, wd1 = 0;
|
||||||
|
uint32_t i2c_data[2];
|
||||||
|
uint8_t i2c_addr, num_wr, num_rd;
|
||||||
|
|
||||||
|
i2c_addr = i2c_inst->i2c_addr;
|
||||||
|
num_wr = i2c_inst->wr_cnt;
|
||||||
|
num_rd = i2c_inst->rd_cnt;
|
||||||
|
if (i2c_addr > 0x7F || num_wr > 129 || num_rd > 128) {
|
||||||
|
return BF_FPGA_EINVAL;
|
||||||
|
}
|
||||||
|
if (i2c_inst->preemt) {
|
||||||
|
wd0 |= I2C_INST_PMT;
|
||||||
|
}
|
||||||
|
if (i2c_inst->en) {
|
||||||
|
wd0 |= I2C_INST_EN;
|
||||||
|
}
|
||||||
|
i2c_data[0] = i2c_data[1] = 0; /* clear on init */
|
||||||
|
switch (i2c_inst->i2c_type) {
|
||||||
|
case BF_FPGA_I2C_NOP:
|
||||||
|
/* add delay + enable */
|
||||||
|
wd0 |= (I2C_NOP | (delay << I2C_DELAY_SHF));
|
||||||
|
break;
|
||||||
|
case BF_FPGA_I2C_WRITE:
|
||||||
|
if (num_wr == 0) {
|
||||||
|
return BF_FPGA_EINVAL;
|
||||||
|
}
|
||||||
|
wd0 |= (I2C_WR_ADDR_DATA | (delay << I2C_DELAY_SHF));
|
||||||
|
wd1 |= (i2c_inst->i2c_addr << I2C_DEV_ADDR_SHF);
|
||||||
|
/* copy the first byte into register address */
|
||||||
|
wd1 |= ((i2c_inst->wr_buf[0]) << I2C_CMD_OFFSET);
|
||||||
|
wd1 |= ((num_wr - 1) << I2C_WR_CNT_SHF);
|
||||||
|
if (num_wr <= 9) {
|
||||||
|
/* copy data into instruction area */
|
||||||
|
memcpy(i2c_data, &i2c_inst->wr_buf[1], (num_wr - 1));
|
||||||
|
bf_fpga_i2c_reg_write32(
|
||||||
|
i2c_ctrl, Bf_FPGA_I2C_INST_DATA_LO(inst_id), i2c_data[0]);
|
||||||
|
bf_fpga_i2c_reg_write32(
|
||||||
|
i2c_ctrl, Bf_FPGA_I2C_INST_DATA_HI(inst_id), i2c_data[1]);
|
||||||
|
} else {
|
||||||
|
/* copy the data in data area */
|
||||||
|
int len = num_wr - 1;
|
||||||
|
uint32_t addr;
|
||||||
|
uint8_t *val = (uint8_t *)(&i2c_inst->wr_buf[1]);
|
||||||
|
/* store the data pointer Note the indexing required by FPGA specs */
|
||||||
|
i2c_data[0] = BF_FPGA_I2C_DATA_AREA(inst_id);
|
||||||
|
addr = i2c_data[0];
|
||||||
|
bf_fpga_i2c_reg_write32(
|
||||||
|
i2c_ctrl, Bf_FPGA_I2C_INST_DATA_LO(inst_id), i2c_data[0] / 4);
|
||||||
|
/* do byte write to avoid endianness mismatch */
|
||||||
|
while (len--) {
|
||||||
|
bf_fpga_i2c_reg_write8(i2c_ctrl, addr, *val);
|
||||||
|
addr++;
|
||||||
|
val++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BF_FPGA_I2C_READ:
|
||||||
|
if (num_rd == 0) {
|
||||||
|
return BF_FPGA_EINVAL;
|
||||||
|
}
|
||||||
|
wd0 |= (I2C_RD_DATA | (delay << I2C_DELAY_SHF));
|
||||||
|
wd1 |= (i2c_inst->i2c_addr << I2C_DEV_ADDR_SHF);
|
||||||
|
wd1 |= ((num_rd) << I2C_RD_CNT_SHF);
|
||||||
|
if (num_rd > 8) {
|
||||||
|
/* store the data area pointer */
|
||||||
|
i2c_data[0] = BF_FPGA_I2C_DATA_AREA(inst_id);
|
||||||
|
bf_fpga_i2c_reg_write32(
|
||||||
|
i2c_ctrl, Bf_FPGA_I2C_INST_DATA_LO(inst_id), i2c_data[0] / 4);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BF_FPGA_I2C_ADDR_READ:
|
||||||
|
if (num_wr == 0 || num_rd == 0) {
|
||||||
|
return BF_FPGA_EINVAL;
|
||||||
|
}
|
||||||
|
wd0 |= (I2C_RD_ADDR_DATA_BURST | (delay << I2C_DELAY_SHF));
|
||||||
|
wd1 |= (i2c_inst->i2c_addr << I2C_DEV_ADDR_SHF);
|
||||||
|
/* 1st byte of the write buf goes into "register address" field */
|
||||||
|
wd1 |= ((num_wr - 1) << I2C_WR_CNT_SHF);
|
||||||
|
wd1 |= ((i2c_inst->wr_buf[0]) << I2C_CMD_OFFSET);
|
||||||
|
wd1 |= ((num_rd) << I2C_RD_CNT_SHF);
|
||||||
|
/* less than 8 bytes data goes to the instruction area */
|
||||||
|
if ((num_wr - 1 + num_rd) <= 8) {
|
||||||
|
memcpy(i2c_data, &i2c_inst->wr_buf[1], (num_wr - 1));
|
||||||
|
bf_fpga_i2c_reg_write32(
|
||||||
|
i2c_ctrl, Bf_FPGA_I2C_INST_DATA_LO(inst_id), i2c_data[0]);
|
||||||
|
bf_fpga_i2c_reg_write32(
|
||||||
|
i2c_ctrl, Bf_FPGA_I2C_INST_DATA_HI(inst_id), i2c_data[1]);
|
||||||
|
} else {
|
||||||
|
int len = num_wr - 1;
|
||||||
|
uint32_t addr;
|
||||||
|
uint8_t *val = (uint8_t *)(&i2c_inst->wr_buf[1]);
|
||||||
|
/* store the data area pointer */
|
||||||
|
i2c_data[0] = BF_FPGA_I2C_DATA_AREA(inst_id);
|
||||||
|
addr = i2c_data[0];
|
||||||
|
bf_fpga_i2c_reg_write32(
|
||||||
|
i2c_ctrl, Bf_FPGA_I2C_INST_DATA_LO(inst_id), i2c_data[0] / 4);
|
||||||
|
/* copy the data in data area */
|
||||||
|
while (len--) {
|
||||||
|
bf_fpga_i2c_reg_write8(i2c_ctrl, addr, *val);
|
||||||
|
addr++;
|
||||||
|
val++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return BF_FPGA_EINVAL;
|
||||||
|
}
|
||||||
|
bf_fpga_i2c_reg_write32(i2c_ctrl, Bf_FPGA_I2C_INST_PARAM(inst_id), wd1);
|
||||||
|
bf_fpga_i2c_reg_write32(i2c_ctrl, Bf_FPGA_I2C_INST_CTRL(inst_id), wd0);
|
||||||
|
return BF_FPGA_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get the i2c completion status of a particular instruction */
|
||||||
|
static uint32_t fpga_i2c_get_status(int bus_id, int inst_id) {
|
||||||
|
fpga_i2c_controller_t *i2c_ctrl = fpga_i2c_ctrl_get(bus_id);
|
||||||
|
uint32_t addr = Bf_FPGA_I2C_INST_CTRL(inst_id);
|
||||||
|
return (bf_fpga_i2c_reg_read32(i2c_ctrl, addr) & I2C_STATUS_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** FPGA I2C data read (assumes locked by caller and no need to stop i2c)
|
||||||
|
*
|
||||||
|
* read the data following a read type i2c operation
|
||||||
|
*
|
||||||
|
* @param bus_id
|
||||||
|
* i2c controller id
|
||||||
|
* @param inst_id
|
||||||
|
* instruction id within this controller space
|
||||||
|
* @param offset
|
||||||
|
* offset in the data-area where read-data is available
|
||||||
|
* @param num_rd
|
||||||
|
* number of bytes to read
|
||||||
|
* @param rd_buf
|
||||||
|
* buffer to read into
|
||||||
|
* @return
|
||||||
|
* 0 on success and <0 on error
|
||||||
|
*/
|
||||||
|
static int fpga_i2c_data_read_locked(fpga_i2c_controller_t *i2c_ctrl,
|
||||||
|
int inst_id,
|
||||||
|
uint8_t offset,
|
||||||
|
uint8_t num_rd,
|
||||||
|
uint8_t *rd_buf) {
|
||||||
|
uint8_t i;
|
||||||
|
uint32_t addr, data_cnt;
|
||||||
|
|
||||||
|
if (!i2c_ctrl || !rd_buf || !num_rd || inst_id < 0 ||
|
||||||
|
inst_id >= FPGA_I2C_NUM_INST) {
|
||||||
|
return BF_FPGA_EINVAL;
|
||||||
|
}
|
||||||
|
/* find out the wr_cnt + rd_cnt from the already executed instruction field */
|
||||||
|
data_cnt = bf_fpga_i2c_reg_read32(i2c_ctrl, Bf_FPGA_I2C_INST_PARAM(inst_id));
|
||||||
|
/* point to data area if the (wr_cnt + rd_cnt) > 8 */
|
||||||
|
data_cnt &= 0xffff; /* retain only the length fields */
|
||||||
|
if (((data_cnt & 0xff) + (data_cnt >> 8)) <= 8) {
|
||||||
|
addr = Bf_FPGA_I2C_INST_DATA_LO(inst_id) + offset;
|
||||||
|
} else {
|
||||||
|
addr = BF_FPGA_I2C_DATA_AREA(inst_id) + offset;
|
||||||
|
}
|
||||||
|
for (i = 0; i < num_rd; i++) {
|
||||||
|
*rd_buf = bf_fpga_i2c_reg_read8(i2c_ctrl, addr);
|
||||||
|
addr++;
|
||||||
|
rd_buf++;
|
||||||
|
}
|
||||||
|
return BF_FPGA_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** FPGA I2C data read
|
||||||
|
*
|
||||||
|
* read the data following a read type i2c operation
|
||||||
|
*
|
||||||
|
* @param bus_id
|
||||||
|
* i2c controller id
|
||||||
|
* @param inst_id
|
||||||
|
* instruction id within this controller space
|
||||||
|
* @param offset
|
||||||
|
* offset in the data-area where read-data is available
|
||||||
|
* @param num_rd
|
||||||
|
* number of bytes to read
|
||||||
|
* @param rd_buf
|
||||||
|
* buffer to read into
|
||||||
|
* @return
|
||||||
|
* 0 on success and <0 on error
|
||||||
|
*/
|
||||||
|
int fpga_i2c_data_read(
|
||||||
|
int bus_id, int inst_id, uint8_t offset, uint8_t num_rd, uint8_t *rd_buf) {
|
||||||
|
fpga_i2c_controller_t *i2c_ctrl = fpga_i2c_ctrl_get(bus_id);
|
||||||
|
int ret;
|
||||||
|
bool i2c_running;
|
||||||
|
uint8_t val;
|
||||||
|
|
||||||
|
if (!i2c_ctrl || !rd_buf || !num_rd || inst_id < 0 ||
|
||||||
|
inst_id >= FPGA_I2C_NUM_INST) {
|
||||||
|
return BF_FPGA_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* aligned (upto) 4 bytes can be read without stopping the ongoing i2c,
|
||||||
|
* this is guaranteed by FPGA design. i2c has to be stopped, in all other
|
||||||
|
* cases, to read a consistent set of read-data.
|
||||||
|
*/
|
||||||
|
if ((offset % 4 == 0) && (num_rd <= 4)) {
|
||||||
|
return (
|
||||||
|
fpga_i2c_data_read_locked(i2c_ctrl, inst_id, offset, num_rd, rd_buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* non-aligned case; stop i2c if running, read data and restart i2c */
|
||||||
|
if (bf_fpga_i2c_lock(i2c_ctrl)) {
|
||||||
|
return BF_FPGA_EAGAIN;
|
||||||
|
}
|
||||||
|
/* check if i2c_controller is running */
|
||||||
|
val = bf_fpga_i2c_reg_read8(i2c_ctrl, Bf_FPGA_TOP_I2C_STATUS);
|
||||||
|
i2c_running = ((val & I2C_STS_BUSY) ? true : false);
|
||||||
|
if (i2c_running) {
|
||||||
|
/* stop ongoing i2c operations */
|
||||||
|
fpga_i2c_stop_locked(i2c_ctrl);
|
||||||
|
}
|
||||||
|
ret = fpga_i2c_data_read_locked(i2c_ctrl, inst_id, offset, num_rd, rd_buf);
|
||||||
|
if (i2c_running) {
|
||||||
|
/* restart ongoing i2c operations */
|
||||||
|
fpga_i2c_start_locked(i2c_ctrl);
|
||||||
|
}
|
||||||
|
bf_fpga_i2c_unlock(i2c_ctrl);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** FPGA I2C onetime i2c operation
|
||||||
|
*
|
||||||
|
* @param i2c_op
|
||||||
|
* bf_fpga_i2c_t parameters * <in/out>
|
||||||
|
* @return
|
||||||
|
* 0 on success and <0 on error
|
||||||
|
*/
|
||||||
|
int fpga_i2c_oneshot(bf_fpga_i2c_t *i2c_op) {
|
||||||
|
int i, ret;
|
||||||
|
uint32_t val;
|
||||||
|
int bus_id;
|
||||||
|
fpga_i2c_controller_t *i2c_ctrl;
|
||||||
|
|
||||||
|
if (!i2c_op) {
|
||||||
|
return BF_FPGA_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bus_id = i2c_op->inst_hndl.bus_id;
|
||||||
|
i2c_ctrl = fpga_i2c_ctrl_get(bus_id);
|
||||||
|
|
||||||
|
if (i2c_op->num_i2c == 0 || i2c_op->num_i2c >= FPGA_I2C_ONESHOT_NUM_INST ||
|
||||||
|
i2c_op->one_time == 0 || bus_id >= BF_I2C_FPGA_NUM_CTRL || !i2c_ctrl) {
|
||||||
|
return BF_FPGA_EINVAL;
|
||||||
|
}
|
||||||
|
if (bf_fpga_i2c_lock(i2c_ctrl)) {
|
||||||
|
return BF_FPGA_EAGAIN;
|
||||||
|
}
|
||||||
|
/* stop ongoing i2c operations */
|
||||||
|
ret = fpga_i2c_stop_locked(i2c_ctrl);
|
||||||
|
if (ret) {
|
||||||
|
bf_fpga_i2c_unlock(i2c_ctrl);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
/* populate one time i2c operation instruction(s) from offset zero */
|
||||||
|
for (i = 0; i < i2c_op->num_i2c; i++) {
|
||||||
|
ret = fpga_i2c_enqueue(bus_id, i, &i2c_op->i2c_inst[i]);
|
||||||
|
if (ret) {
|
||||||
|
goto oneshot_error_exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* start i2c operations */
|
||||||
|
ret = fpga_i2c_start_locked(i2c_ctrl);
|
||||||
|
if (ret) {
|
||||||
|
goto oneshot_error_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* wait until complete and read the data if necessary */
|
||||||
|
for (i = 0; i < i2c_op->num_i2c; i++) {
|
||||||
|
int cnt;
|
||||||
|
val = 0;
|
||||||
|
/* cnt is roughly the number of bytes of this i2c cycle
|
||||||
|
* overhead of 100 bytes for for worst case timeout, one
|
||||||
|
* should not hit that in normal working case
|
||||||
|
*/
|
||||||
|
cnt = i2c_op->i2c_inst[i].wr_cnt + i2c_op->i2c_inst[i].rd_cnt;
|
||||||
|
/* bump up the cnt for an i2c transaction containing some data
|
||||||
|
* for computing worst case timeout */
|
||||||
|
if (cnt > 0) {
|
||||||
|
cnt = cnt + 100;
|
||||||
|
}
|
||||||
|
while (!(val & I2C_STATUS_COMPLETED) && (cnt-- > 0)) {
|
||||||
|
/* 1 byte ~= 10 bits takes 25 microsec on i2c cycle at 400khz */
|
||||||
|
bf_fpga_us_delay(50);
|
||||||
|
val = fpga_i2c_get_status(bus_id, i);
|
||||||
|
}
|
||||||
|
i2c_op->i2c_inst[i].status = val; /* store the h/w status */
|
||||||
|
if (val & I2C_STATUS_ERR_MASK) {
|
||||||
|
ret = BF_FPGA_EIO;
|
||||||
|
goto oneshot_error_exit;
|
||||||
|
}
|
||||||
|
if (i2c_op->i2c_inst[i].rd_cnt) {
|
||||||
|
uint8_t offset = 0;
|
||||||
|
if (i2c_op->i2c_inst[i].wr_cnt > 1) {
|
||||||
|
offset = i2c_op->i2c_inst[i].wr_cnt - 1;
|
||||||
|
}
|
||||||
|
if (fpga_i2c_data_read_locked(i2c_ctrl,
|
||||||
|
i,
|
||||||
|
offset,
|
||||||
|
i2c_op->i2c_inst[i].rd_cnt,
|
||||||
|
i2c_op->i2c_inst[i].rd_buf)) {
|
||||||
|
ret = BF_FPGA_EIO;
|
||||||
|
goto oneshot_error_exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret = BF_FPGA_OK;
|
||||||
|
|
||||||
|
oneshot_error_exit:
|
||||||
|
for (i = 0; i < i2c_op->num_i2c; i++) {
|
||||||
|
/* cleanup the enable bit */
|
||||||
|
val = bf_fpga_i2c_reg_read32(i2c_ctrl, Bf_FPGA_I2C_INST_CTRL(i));
|
||||||
|
val &= (~I2C_INST_EN);
|
||||||
|
bf_fpga_i2c_reg_write32(i2c_ctrl, Bf_FPGA_I2C_INST_CTRL(i), val);
|
||||||
|
}
|
||||||
|
bf_fpga_i2c_unlock(i2c_ctrl);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** FPGA I2C insert periodic i2c operation
|
||||||
|
*
|
||||||
|
* @param i2c_op
|
||||||
|
* bf_fpga_i2c_t parameters * <in/out>
|
||||||
|
* @return
|
||||||
|
* 0 on success and <0 on error
|
||||||
|
*/
|
||||||
|
int fpga_i2c_pr_add(bf_fpga_i2c_t *i2c_op) {
|
||||||
|
fpga_i2c_controller_t *i2c_ctrl;
|
||||||
|
int i, ret, next_id;
|
||||||
|
bool preemt;
|
||||||
|
|
||||||
|
if (!i2c_op) {
|
||||||
|
return BF_FPGA_EINVAL;
|
||||||
|
}
|
||||||
|
i2c_ctrl = fpga_i2c_ctrl_get(i2c_op->inst_hndl.bus_id);
|
||||||
|
if (!i2c_ctrl) {
|
||||||
|
return BF_FPGA_EINVAL;
|
||||||
|
}
|
||||||
|
if (bf_fpga_i2c_lock(i2c_ctrl)) {
|
||||||
|
return BF_FPGA_EAGAIN;
|
||||||
|
}
|
||||||
|
/* get the next available free slot */
|
||||||
|
next_id = get_next_free_index(i2c_ctrl, i2c_op->num_i2c, true);
|
||||||
|
if (next_id < 0) {
|
||||||
|
bf_fpga_i2c_unlock(i2c_ctrl);
|
||||||
|
return BF_FPGA_EBUSY;
|
||||||
|
}
|
||||||
|
/* populate periodic i2c operation instruction(s) */
|
||||||
|
for (i = 0; i < i2c_op->num_i2c; i++) {
|
||||||
|
preemt = ((i == (i2c_op->num_i2c - 1)) ? false : true);
|
||||||
|
i2c_op->i2c_inst[i].preemt = preemt;
|
||||||
|
ret = fpga_i2c_enqueue(
|
||||||
|
i2c_op->inst_hndl.bus_id, next_id + i, &i2c_op->i2c_inst[i]);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
bf_fpga_i2c_unlock(i2c_ctrl);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bf_fpga_i2c_unlock(i2c_ctrl);
|
||||||
|
i2c_op->inst_hndl.inst_id = next_id;
|
||||||
|
return BF_FPGA_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** FPGA I2C remove periodic i2c operation(s) from instruction memory
|
||||||
|
*
|
||||||
|
* @param i2c_op
|
||||||
|
* bf_fpga_i2c_t parameters * <in/out>
|
||||||
|
* @return
|
||||||
|
* 0 on success and <0 on error
|
||||||
|
*/
|
||||||
|
int fpga_i2c_del(bf_fpga_i2c_t *i2c_op) {
|
||||||
|
fpga_i2c_controller_t *i2c_ctrl;
|
||||||
|
int i, inst_id;
|
||||||
|
|
||||||
|
if (!i2c_op) {
|
||||||
|
return BF_FPGA_EINVAL;
|
||||||
|
}
|
||||||
|
i2c_ctrl = fpga_i2c_ctrl_get(i2c_op->inst_hndl.bus_id);
|
||||||
|
if (!i2c_ctrl) {
|
||||||
|
return BF_FPGA_EINVAL;
|
||||||
|
}
|
||||||
|
inst_id = i2c_op->inst_hndl.inst_id;
|
||||||
|
if (bf_fpga_i2c_lock(i2c_ctrl)) {
|
||||||
|
return BF_FPGA_EAGAIN;
|
||||||
|
}
|
||||||
|
for (i = 0; i < i2c_op->num_i2c; i++) {
|
||||||
|
/* nullify the instruction */
|
||||||
|
bf_fpga_i2c_reg_write32(i2c_ctrl, Bf_FPGA_I2C_INST_CTRL(inst_id + i), 0);
|
||||||
|
}
|
||||||
|
/* reset the in_use flag */
|
||||||
|
release_index(i2c_ctrl, inst_id, i2c_op->num_i2c);
|
||||||
|
bf_fpga_i2c_unlock(i2c_ctrl);
|
||||||
|
return BF_FPGA_OK;
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
Barefoot Networks FPGA Linux driver
|
||||||
|
Copyright(c) 2018 - 2019 Barefoot Networks, Inc.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it
|
||||||
|
under the terms and conditions of the GNU General Public License,
|
||||||
|
version 2, as published by the Free Software Foundation.
|
||||||
|
|
||||||
|
This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
The full GNU General Public License is included in this distribution in
|
||||||
|
the file called "COPYING".
|
||||||
|
|
||||||
|
Contact Information:
|
||||||
|
info@barefootnetworks.com
|
||||||
|
Barefoot Networks, 4750 Patrick Henry Drive, Santa Clara CA 95054
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
#ifndef _BF_FPGA_I2C_H
|
||||||
|
#define _BF_FPGA_I2C_H
|
||||||
|
|
||||||
|
/* Allow the use in C++ code. */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int fpga_i2c_start(int bus_id);
|
||||||
|
int fpga_i2c_stop(int bus_id);
|
||||||
|
int fpga_i2c_reset(int bus_id);
|
||||||
|
int fpga_i2c_is_busy(int bus_id, bool *is_busy);
|
||||||
|
int fpga_i2c_inst_en(int bus_id, int inst_id, bool en);
|
||||||
|
int fpga_i2c_set_clk(int bus_id, int clock_div);
|
||||||
|
int fpga_i2c_controller_init(int bus_id);
|
||||||
|
int fpga_i2c_controller_cleanup(int bus_id);
|
||||||
|
int fpga_i2c_init(uint8_t *base_addr);
|
||||||
|
void fpga_i2c_deinit(void);
|
||||||
|
int fpga_i2c_oneshot(bf_fpga_i2c_t *i2c_op);
|
||||||
|
int fpga_i2c_pr_add(bf_fpga_i2c_t *i2c_op);
|
||||||
|
int fpga_i2c_del(bf_fpga_i2c_t *i2c_op);
|
||||||
|
int fpga_i2c_data_read(
|
||||||
|
int bus_id, int inst_id, uint8_t offset, uint8_t len, uint8_t *buf);
|
||||||
|
bool fpga_i2c_is_inited(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* C++ */
|
||||||
|
|
||||||
|
#endif /* _BF_FPGA_I2C_H */
|
@ -0,0 +1,397 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
Barefoot Networks FPGA Linux driver
|
||||||
|
Copyright(c) 2018 - 2019 Barefoot Networks, Inc.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it
|
||||||
|
under the terms and conditions of the GNU General Public License,
|
||||||
|
version 2, as published by the Free Software Foundation.
|
||||||
|
|
||||||
|
This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
The full GNU General Public License is included in this distribution in
|
||||||
|
the file called "COPYING".
|
||||||
|
|
||||||
|
Contact Information:
|
||||||
|
info@barefootnetworks.com
|
||||||
|
Barefoot Networks, 4750 Patrick Henry Drive, Santa Clara CA 95054
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include "bf_fpga_i2c_priv_porting.h"
|
||||||
|
#include <bf_fpga_ioctl.h>
|
||||||
|
#include "bf_fpga_i2c.h"
|
||||||
|
#include "bf_fpga_i2c_priv.h"
|
||||||
|
#include "bf_fpga_i2c_reg.h"
|
||||||
|
|
||||||
|
/* static i2c controller contents */
|
||||||
|
static fpga_i2c_controller_t fpga_i2c_ctrl[BF_I2C_FPGA_NUM_CTRL];
|
||||||
|
static bool fpga_i2c_inited = false;
|
||||||
|
|
||||||
|
/* fpga memory space access APIs */
|
||||||
|
/* 32 bit write into fpga BAR0 */
|
||||||
|
void bf_fpga_reg_write(fpga_i2c_controller_t *i2c_ctrl,
|
||||||
|
uint32_t offset,
|
||||||
|
uint32_t val) {
|
||||||
|
uint8_t *ptr = i2c_ctrl->fpga_base_addr + offset;
|
||||||
|
bf_fpga_write32(ptr, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 32 bit read into fpga BAR0 */
|
||||||
|
uint32_t bf_fpga_reg_read(fpga_i2c_controller_t *i2c_ctrl, uint32_t offset) {
|
||||||
|
uint8_t *ptr = i2c_ctrl->fpga_base_addr + offset;
|
||||||
|
return (bf_fpga_read32(ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 32 bit write into fpga i2c space */
|
||||||
|
void bf_fpga_i2c_reg_write32(fpga_i2c_controller_t *i2c_ctrl,
|
||||||
|
uint32_t offset,
|
||||||
|
uint32_t val) {
|
||||||
|
uint8_t *ptr = i2c_ctrl->i2c_base_addr + offset;
|
||||||
|
bf_fpga_write32(ptr, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 32 bit read into fpga i2c space */
|
||||||
|
uint32_t bf_fpga_i2c_reg_read32(fpga_i2c_controller_t *i2c_ctrl,
|
||||||
|
uint32_t offset) {
|
||||||
|
uint8_t *ptr = i2c_ctrl->i2c_base_addr + offset;
|
||||||
|
return (bf_fpga_read32(ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 8 bit write into fpga i2c space */
|
||||||
|
void bf_fpga_i2c_reg_write8(fpga_i2c_controller_t *i2c_ctrl,
|
||||||
|
uint32_t offset,
|
||||||
|
uint8_t val) {
|
||||||
|
uint8_t *ptr = i2c_ctrl->i2c_base_addr + offset;
|
||||||
|
bf_fpga_write8(ptr, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 8 bit read into fpga i2c space */
|
||||||
|
uint8_t bf_fpga_i2c_reg_read8(fpga_i2c_controller_t *i2c_ctrl,
|
||||||
|
uint32_t offset) {
|
||||||
|
uint8_t *ptr = i2c_ctrl->i2c_base_addr + offset;
|
||||||
|
return (bf_fpga_read8(ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
int bf_fpga_i2c_lock(fpga_i2c_controller_t *i2c_ctrl) {
|
||||||
|
return (bf_fpga_cr_enter(&i2c_ctrl->fpga_ctrl_lock));
|
||||||
|
}
|
||||||
|
|
||||||
|
void bf_fpga_i2c_unlock(fpga_i2c_controller_t *i2c_ctrl) {
|
||||||
|
return (bf_fpga_cr_leave(&i2c_ctrl->fpga_ctrl_lock));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** FPGA return pointer to i2c_controller struct
|
||||||
|
*
|
||||||
|
* @param bus_id
|
||||||
|
* i2c controller id
|
||||||
|
* @return
|
||||||
|
* pointer to i2c_controller struct of <bus_id>
|
||||||
|
*/
|
||||||
|
fpga_i2c_controller_t *fpga_i2c_ctrl_get(int bus_id) {
|
||||||
|
if (bus_id >= BF_I2C_FPGA_NUM_CTRL) {
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
return &fpga_i2c_ctrl[bus_id];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* is fpga module is soft inited */
|
||||||
|
bool fpga_i2c_is_inited() { return fpga_i2c_inited; }
|
||||||
|
|
||||||
|
/** FPGA I2C set clock: sets clock of i2c operations
|
||||||
|
*
|
||||||
|
* controller must be stopped before, if applicable.
|
||||||
|
*
|
||||||
|
* @param bus_id
|
||||||
|
* i2c controller id
|
||||||
|
* @param clk_div
|
||||||
|
* clock divider value as per fpga specs
|
||||||
|
* @return
|
||||||
|
* 0 on success and <0 on error
|
||||||
|
*/
|
||||||
|
int fpga_i2c_set_clk(int bus_id, int clk_div) {
|
||||||
|
uint32_t val;
|
||||||
|
fpga_i2c_controller_t *i2c_ctrl;
|
||||||
|
|
||||||
|
if (bus_id >= BF_I2C_FPGA_NUM_CTRL) {
|
||||||
|
return BF_FPGA_EINVAL;
|
||||||
|
}
|
||||||
|
i2c_ctrl = fpga_i2c_ctrl_get(bus_id);
|
||||||
|
if (bf_fpga_i2c_lock(i2c_ctrl)) {
|
||||||
|
return BF_FPGA_EAGAIN;
|
||||||
|
}
|
||||||
|
clk_div = (clk_div & I2C_CTRL_CLK_DIV_MASK) << I2C_CTRL_CLK_DIV_SHF;
|
||||||
|
val = bf_fpga_i2c_reg_read32(i2c_ctrl, Bf_FPGA_I2C_CTRL_TOP);
|
||||||
|
val &= ~(I2C_CTRL_CLK_DIV_MASK << I2C_CTRL_CLK_DIV_SHF);
|
||||||
|
val |= clk_div;
|
||||||
|
bf_fpga_i2c_reg_write32(i2c_ctrl, Bf_FPGA_I2C_CTRL_TOP, val);
|
||||||
|
bf_fpga_i2c_unlock(i2c_ctrl);
|
||||||
|
return BF_FPGA_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** FPGA I2C stop : stops ongoing i2c operations without mutex locking
|
||||||
|
*
|
||||||
|
* internal function
|
||||||
|
*
|
||||||
|
* @param bus_id
|
||||||
|
* i2c controller struct
|
||||||
|
* @return
|
||||||
|
* 0 on success and <0 on error
|
||||||
|
*/
|
||||||
|
int fpga_i2c_stop_locked(fpga_i2c_controller_t *i2c_ctrl) {
|
||||||
|
int to_ms, ret;
|
||||||
|
uint8_t val;
|
||||||
|
|
||||||
|
val = bf_fpga_i2c_reg_read8(i2c_ctrl, Bf_FPGA_I2C_CTRL_TOP);
|
||||||
|
val &= ~I2C_CTRL_START;
|
||||||
|
bf_fpga_i2c_reg_write8(i2c_ctrl, Bf_FPGA_I2C_CTRL_TOP, val);
|
||||||
|
|
||||||
|
to_ms = 100; /* 5 msec converted to multiple of 50 micro sec */
|
||||||
|
val = bf_fpga_i2c_reg_read8(i2c_ctrl, Bf_FPGA_TOP_I2C_STATUS);
|
||||||
|
while ((val & I2C_STS_BUSY) && to_ms) {
|
||||||
|
bf_fpga_us_delay(50);
|
||||||
|
to_ms--;
|
||||||
|
val = bf_fpga_i2c_reg_read8(i2c_ctrl, Bf_FPGA_TOP_I2C_STATUS);
|
||||||
|
}
|
||||||
|
if (to_ms > 0) {
|
||||||
|
ret = BF_FPGA_OK;
|
||||||
|
} else {
|
||||||
|
ret = BF_FPGA_EIO;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** FPGA I2C start : starts i2c operations without mutex locking
|
||||||
|
*
|
||||||
|
* internal function
|
||||||
|
*
|
||||||
|
* @param bus_id
|
||||||
|
* i2c controller struct
|
||||||
|
* @return
|
||||||
|
* 0 on success and <0 on error
|
||||||
|
*/
|
||||||
|
int fpga_i2c_start_locked(fpga_i2c_controller_t *i2c_ctrl) {
|
||||||
|
uint8_t val;
|
||||||
|
val = bf_fpga_i2c_reg_read8(i2c_ctrl, Bf_FPGA_I2C_CTRL_TOP);
|
||||||
|
bf_fpga_i2c_reg_write8(i2c_ctrl, Bf_FPGA_I2C_CTRL_TOP, val | I2C_CTRL_START);
|
||||||
|
return BF_FPGA_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** FPGA I2C stop : stops ongoing i2c operations
|
||||||
|
*
|
||||||
|
* @param bus_id
|
||||||
|
* i2c controller id
|
||||||
|
* @return
|
||||||
|
* 0 on success and <0 on error
|
||||||
|
*/
|
||||||
|
int fpga_i2c_stop(int bus_id) {
|
||||||
|
fpga_i2c_controller_t *i2c_ctrl;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (bus_id >= BF_I2C_FPGA_NUM_CTRL || !fpga_i2c_is_inited()) {
|
||||||
|
return BF_FPGA_EINVAL;
|
||||||
|
}
|
||||||
|
i2c_ctrl = fpga_i2c_ctrl_get(bus_id);
|
||||||
|
if (bf_fpga_i2c_lock(i2c_ctrl)) {
|
||||||
|
return BF_FPGA_EAGAIN;
|
||||||
|
}
|
||||||
|
ret = fpga_i2c_stop_locked(i2c_ctrl);
|
||||||
|
bf_fpga_i2c_unlock(i2c_ctrl);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** FPGA I2C start : starts i2c operations
|
||||||
|
*
|
||||||
|
* @param bus_id
|
||||||
|
* i2c controller id
|
||||||
|
* @return
|
||||||
|
* 0 on success and <0 on error
|
||||||
|
*/
|
||||||
|
int fpga_i2c_start(int bus_id) {
|
||||||
|
fpga_i2c_controller_t *i2c_ctrl;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (bus_id >= BF_I2C_FPGA_NUM_CTRL || !fpga_i2c_is_inited()) {
|
||||||
|
return BF_FPGA_EINVAL;
|
||||||
|
}
|
||||||
|
i2c_ctrl = fpga_i2c_ctrl_get(bus_id);
|
||||||
|
if (bf_fpga_i2c_lock(i2c_ctrl)) {
|
||||||
|
return BF_FPGA_EAGAIN;
|
||||||
|
}
|
||||||
|
ret = fpga_i2c_start_locked(i2c_ctrl);
|
||||||
|
bf_fpga_i2c_unlock(i2c_ctrl);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** FPGA I2C reset: reset i2c by issuing 9 clocks in a specific way
|
||||||
|
*
|
||||||
|
* @param bus_id
|
||||||
|
* i2c controller id
|
||||||
|
* @return
|
||||||
|
* 0 on success and <0 on error
|
||||||
|
*/
|
||||||
|
int fpga_i2c_reset(int bus_id) {
|
||||||
|
fpga_i2c_controller_t *i2c_ctrl;
|
||||||
|
|
||||||
|
if (bus_id >= BF_I2C_FPGA_NUM_CTRL || !fpga_i2c_is_inited()) {
|
||||||
|
return BF_FPGA_EINVAL;
|
||||||
|
}
|
||||||
|
i2c_ctrl = fpga_i2c_ctrl_get(bus_id);
|
||||||
|
if (bf_fpga_i2c_lock(i2c_ctrl)) {
|
||||||
|
return BF_FPGA_EAGAIN;
|
||||||
|
}
|
||||||
|
bf_fpga_i2c_reg_write8(i2c_ctrl, Bf_FPGA_I2C_CTRL_TOP, I2C_CTRL_RESET);
|
||||||
|
bf_fpga_i2c_unlock(i2c_ctrl);
|
||||||
|
return BF_FPGA_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** FPGA I2C is running?
|
||||||
|
*
|
||||||
|
* @param bus_id
|
||||||
|
* i2c controller id
|
||||||
|
* @return
|
||||||
|
* 0 on success and <0 on error
|
||||||
|
*/
|
||||||
|
int fpga_i2c_is_busy(int bus_id, bool *busy) {
|
||||||
|
uint8_t val;
|
||||||
|
fpga_i2c_controller_t *i2c_ctrl;
|
||||||
|
|
||||||
|
if (bus_id >= BF_I2C_FPGA_NUM_CTRL || !fpga_i2c_is_inited()) {
|
||||||
|
return BF_FPGA_EINVAL;
|
||||||
|
}
|
||||||
|
i2c_ctrl = fpga_i2c_ctrl_get(bus_id);
|
||||||
|
if (bf_fpga_i2c_lock(i2c_ctrl)) {
|
||||||
|
return BF_FPGA_EAGAIN;
|
||||||
|
}
|
||||||
|
val = bf_fpga_i2c_reg_read8(i2c_ctrl, Bf_FPGA_TOP_I2C_STATUS);
|
||||||
|
*busy = ((val & I2C_STS_BUSY) ? true : false);
|
||||||
|
bf_fpga_i2c_unlock(i2c_ctrl);
|
||||||
|
return BF_FPGA_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** FPGA I2C instruction enable/disable
|
||||||
|
*
|
||||||
|
* enable or disable a particular instruction in i2c instruction memory
|
||||||
|
* @param bus_id
|
||||||
|
* i2c controller id
|
||||||
|
* @param inst_id
|
||||||
|
* instruction id within this controller space
|
||||||
|
* @param en
|
||||||
|
* true for enable, false for disable
|
||||||
|
* @return
|
||||||
|
* 0 on success and <0 on error
|
||||||
|
*/
|
||||||
|
int fpga_i2c_inst_en(int bus_id, int inst_id, bool en) {
|
||||||
|
uint32_t val;
|
||||||
|
fpga_i2c_controller_t *i2c_ctrl;
|
||||||
|
|
||||||
|
if (bus_id >= BF_I2C_FPGA_NUM_CTRL || !fpga_i2c_is_inited()) {
|
||||||
|
return BF_FPGA_EINVAL;
|
||||||
|
}
|
||||||
|
if (inst_id < 0 || inst_id >= FPGA_I2C_NUM_INST) {
|
||||||
|
return BF_FPGA_EINVAL;
|
||||||
|
}
|
||||||
|
i2c_ctrl = fpga_i2c_ctrl_get(bus_id);
|
||||||
|
if (bf_fpga_i2c_lock(i2c_ctrl)) {
|
||||||
|
return BF_FPGA_EAGAIN;
|
||||||
|
}
|
||||||
|
val = bf_fpga_i2c_reg_read32(i2c_ctrl, Bf_FPGA_I2C_INST_CTRL(inst_id));
|
||||||
|
if (en) {
|
||||||
|
val |= I2C_INST_EN;
|
||||||
|
} else {
|
||||||
|
val &= ~I2C_INST_EN;
|
||||||
|
}
|
||||||
|
bf_fpga_i2c_reg_write32(i2c_ctrl, Bf_FPGA_I2C_INST_CTRL(inst_id), val);
|
||||||
|
fpga_i2c_ctrl[bus_id].i2c_inst[inst_id].en = en;
|
||||||
|
bf_fpga_i2c_unlock(i2c_ctrl);
|
||||||
|
return BF_FPGA_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** FPGA I2C controller initialization
|
||||||
|
*
|
||||||
|
* @param bus_id
|
||||||
|
* i2c controller id
|
||||||
|
* @return
|
||||||
|
* 0 on success and <0 on error
|
||||||
|
*/
|
||||||
|
int fpga_i2c_controller_init(int bus_id) {
|
||||||
|
fpga_i2c_controller_t *i2c_ctrl;
|
||||||
|
int i, ret;
|
||||||
|
|
||||||
|
if (bus_id >= BF_I2C_FPGA_NUM_CTRL) {
|
||||||
|
return BF_FPGA_EINVAL;
|
||||||
|
}
|
||||||
|
i2c_ctrl = fpga_i2c_ctrl_get(bus_id);
|
||||||
|
if (!i2c_ctrl) {
|
||||||
|
return BF_FPGA_EINVAL;
|
||||||
|
}
|
||||||
|
bf_fpga_fast_lock_init(&i2c_ctrl->spinlock, 0);
|
||||||
|
bf_fpga_cr_init(&i2c_ctrl->fpga_ctrl_lock);
|
||||||
|
bf_fpga_cr_enter(&i2c_ctrl->fpga_ctrl_lock);
|
||||||
|
for (i = 0; i < FPGA_I2C_NUM_INST; i++) {
|
||||||
|
fpga_i2c_ctrl[bus_id].i2c_inst[i].inst = (uint32_t)i;
|
||||||
|
bf_fpga_i2c_reg_write32(i2c_ctrl, Bf_FPGA_I2C_INST_CTRL(i), 0);
|
||||||
|
}
|
||||||
|
bf_fpga_cr_leave(&i2c_ctrl->fpga_ctrl_lock);
|
||||||
|
ret = fpga_i2c_set_clk(bus_id, 1); /* 400 khz default */
|
||||||
|
ret |= fpga_i2c_stop(bus_id); /* just in case */
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** FPGA I2C controller de initialization
|
||||||
|
*
|
||||||
|
* @param bus_id
|
||||||
|
* i2c controller id
|
||||||
|
* @return
|
||||||
|
* 0 on success and <0 on error
|
||||||
|
*/
|
||||||
|
int fpga_i2c_controller_cleanup(int bus_id) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
fpga_i2c_stop(bus_id);
|
||||||
|
for (i = 0; i < FPGA_I2C_NUM_INST; i++) {
|
||||||
|
fpga_i2c_ctrl[bus_id].i2c_inst[i].en = false;
|
||||||
|
}
|
||||||
|
bf_fpga_cr_destroy(&fpga_i2c_ctrl[bus_id].fpga_ctrl_lock);
|
||||||
|
bf_fpga_fast_lock_destroy(&fpga_i2c_ctrl[bus_id].spinlock);
|
||||||
|
return BF_FPGA_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** FPGA I2C global initialization
|
||||||
|
*
|
||||||
|
* @param base_addr
|
||||||
|
* virtual address of i2c memory relative to BAR0 base
|
||||||
|
* @return
|
||||||
|
* 0 on success and <0 on error
|
||||||
|
*/
|
||||||
|
int fpga_i2c_init(uint8_t *base_addr) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
memset(fpga_i2c_ctrl, 0, sizeof(fpga_i2c_ctrl));
|
||||||
|
for (i = 0; i < BF_I2C_FPGA_NUM_CTRL; i++) {
|
||||||
|
fpga_i2c_ctrl[i].i2c_base_addr = base_addr + BF_FPGA_I2C_CTRL_BASE_ADDR(i);
|
||||||
|
fpga_i2c_ctrl[i].fpga_base_addr = base_addr;
|
||||||
|
fpga_i2c_controller_init(i);
|
||||||
|
}
|
||||||
|
fpga_i2c_inited = true;
|
||||||
|
return BF_FPGA_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** FPGA I2C global de initialization
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void fpga_i2c_deinit(void) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < BF_I2C_FPGA_NUM_CTRL; i++) {
|
||||||
|
fpga_i2c_controller_cleanup(i);
|
||||||
|
}
|
||||||
|
fpga_i2c_inited = false;
|
||||||
|
}
|
@ -0,0 +1,150 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
Barefoot Networks FPGA Linux driver
|
||||||
|
Copyright(c) 2018 - 2019 Barefoot Networks, Inc.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it
|
||||||
|
under the terms and conditions of the GNU General Public License,
|
||||||
|
version 2, as published by the Free Software Foundation.
|
||||||
|
|
||||||
|
This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
The full GNU General Public License is included in this distribution in
|
||||||
|
the file called "COPYING".
|
||||||
|
|
||||||
|
Contact Information:
|
||||||
|
info@barefootnetworks.com
|
||||||
|
Barefoot Networks, 4750 Patrick Henry Drive, Santa Clara CA 95054
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/vmalloc.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/bitops.h>
|
||||||
|
#include "bf_fpga_i2c_priv_porting.h"
|
||||||
|
#include <bf_fpga_ioctl.h>
|
||||||
|
#include "bf_fpga_i2c.h"
|
||||||
|
#include "bf_fpga_i2c_priv.h"
|
||||||
|
|
||||||
|
/* This file contains OS and system specific porting functions for i2c APIs.
|
||||||
|
* Implementation in this file is for porting to linux kernel.
|
||||||
|
*/
|
||||||
|
/* mutex APIs are for mutual exclusion with capability to sleep while in
|
||||||
|
* exclusion mode
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* sleepable virtual exclusion region */
|
||||||
|
typedef struct {
|
||||||
|
atomic_t lock_state; /* 1: in exclusion mode, 0: not in exclusion mode */
|
||||||
|
} sleepable_v_mutex_t;
|
||||||
|
|
||||||
|
int bf_fpga_cr_init(bf_fpga_mutex_t *lock) {
|
||||||
|
sleepable_v_mutex_t *mtx;
|
||||||
|
|
||||||
|
if (!lock) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
mtx = vzalloc(sizeof(sleepable_v_mutex_t));
|
||||||
|
|
||||||
|
if (mtx) {
|
||||||
|
atomic_set(&mtx->lock_state, 0);
|
||||||
|
*lock = (bf_fpga_mutex_t *)mtx;
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
*lock = NULL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bf_fpga_cr_destroy(bf_fpga_mutex_t *lock) {
|
||||||
|
if (lock && *lock) {
|
||||||
|
vfree(*lock);
|
||||||
|
*lock = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bf_fpga_cr_leave(bf_fpga_mutex_t *lock) {
|
||||||
|
sleepable_v_mutex_t *mtx;
|
||||||
|
|
||||||
|
if (lock && *lock) {
|
||||||
|
mtx = (sleepable_v_mutex_t *)*lock;
|
||||||
|
atomic_xchg(&mtx->lock_state, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int bf_fpga_cr_enter(bf_fpga_mutex_t *lock) {
|
||||||
|
sleepable_v_mutex_t *mtx;
|
||||||
|
|
||||||
|
/* All we do here is: test and set <lock_state> */
|
||||||
|
if (lock && *lock) {
|
||||||
|
int cnt = 10000; /* This will provide maximum of 500-1000 ms timeout */
|
||||||
|
mtx = (sleepable_v_mutex_t *)*lock;
|
||||||
|
while (atomic_cmpxchg(&mtx->lock_state, 0, 1) != 0) {
|
||||||
|
if (cnt-- <= 0) {
|
||||||
|
return -1; /* this is a worst case timeout situation */
|
||||||
|
}
|
||||||
|
usleep_range(50, 100); /* 50 us = about 2 bytes at 400Kbs i2c */
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* **** not implemented in current mode of locking */
|
||||||
|
int bf_fpga_mutex_trylock(bf_fpga_mutex_t *lock) {
|
||||||
|
if (lock && *lock) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fast lock is a non-blocking busy lock, implemented with spinlock */
|
||||||
|
int bf_fpga_fast_lock_init(bf_fpga_fast_lock_t *sl, unsigned int initial) {
|
||||||
|
spinlock_t *slock;
|
||||||
|
|
||||||
|
(void)initial;
|
||||||
|
if (!sl) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
slock = vzalloc(sizeof(spinlock_t));
|
||||||
|
|
||||||
|
if (slock) {
|
||||||
|
spin_lock_init(slock);
|
||||||
|
*sl = (bf_fpga_fast_lock_t *)slock;
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
*sl = NULL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bf_fpga_fast_lock_destroy(bf_fpga_fast_lock_t *sl) {
|
||||||
|
if (sl && *sl) {
|
||||||
|
vfree(*sl);
|
||||||
|
*sl = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int bf_fpga_fast_lock(bf_fpga_fast_lock_t *sl) {
|
||||||
|
if (sl && *sl) {
|
||||||
|
spin_lock(*sl);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bf_fpga_fast_unlock(bf_fpga_fast_lock_t *sl) {
|
||||||
|
if (sl && *sl) {
|
||||||
|
spin_unlock(*sl);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,104 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
Barefoot Networks FPGA Linux driver
|
||||||
|
Copyright(c) 2018 - 2019 Barefoot Networks, Inc.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it
|
||||||
|
under the terms and conditions of the GNU General Public License,
|
||||||
|
version 2, as published by the Free Software Foundation.
|
||||||
|
|
||||||
|
This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
The full GNU General Public License is included in this distribution in
|
||||||
|
the file called "COPYING".
|
||||||
|
|
||||||
|
Contact Information:
|
||||||
|
info@barefootnetworks.com
|
||||||
|
Barefoot Networks, 4750 Patrick Henry Drive, Santa Clara CA 95054
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
#ifndef _BF_FPGA_I2C_PRIV_H
|
||||||
|
#define _BF_FPGA_I2C_PRIV_H
|
||||||
|
|
||||||
|
/* Allow the use in C++ code. */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define FPGA_I2C_INST_OFFSET(idx) (0x10 + (16 * idx))
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
FGPA_I2C_NOP = 0x0,
|
||||||
|
FGPA_I2C_WR_ADDR_DATA = 0x1, /* wr: reg_addr, wr: data */
|
||||||
|
FGPA_I2C_WR_ADDR_RD_DATA = 0x2, /* wr: reg_addrss, r/s, rd: data */
|
||||||
|
FGPA_I2C_WR_ADDR = 0x3, /* wr: reg_addr */
|
||||||
|
FGPA_I2C_RD_DATA = 0x4, /* rd: data */
|
||||||
|
FGPA_I2C_MULTI_WR_RD = 0x5 /* wr: n bytes, r/s, rd: m bytes */
|
||||||
|
} i2c_cmd_type;
|
||||||
|
|
||||||
|
/* contents of each instruction instance */
|
||||||
|
typedef struct i2c_inst_cmd_s {
|
||||||
|
i2c_cmd_type i2c_cmd; /* i2x cycle type */
|
||||||
|
uint32_t data_lo; /* lower 4 bytes of data associated with this inst */
|
||||||
|
uint32_t data_hi; /* upper 4 bytes of data associated with this inst */
|
||||||
|
uint32_t us_delay; /* delay before i2c cycle */
|
||||||
|
uint8_t i2c_addr; /* i2c device address, in 7 bit format */
|
||||||
|
uint8_t reg_addr; /* 1st write byte, if present in i2c cycle */
|
||||||
|
uint8_t num_read; /* number of bytes to write excluding reg_addr */
|
||||||
|
uint8_t num_write; /* number of bytes to read */
|
||||||
|
} i2c_inst_cmd_t;
|
||||||
|
|
||||||
|
/* attributes of each instruction instance */
|
||||||
|
typedef struct i2c_inst_s {
|
||||||
|
uint32_t inst; /* index of the instruction within the controller memory */
|
||||||
|
bool en; /* is instruction enabled */
|
||||||
|
bool preemt; /* atomically execute next instruction */
|
||||||
|
bool int_en; /* enable interrupt after execution */
|
||||||
|
bool in_use; /* is this instruction currently used */
|
||||||
|
} i2c_inst_t;
|
||||||
|
|
||||||
|
typedef struct fpga_i2c_controller_s {
|
||||||
|
bf_fpga_mutex_t fpga_ctrl_lock;
|
||||||
|
bf_fpga_fast_lock_t spinlock;
|
||||||
|
uint8_t *fpga_base_addr; /* virtual address of start of fpga memory */
|
||||||
|
uint8_t *i2c_base_addr; /* virtual address of i2c controller memory */
|
||||||
|
uint32_t start; /* offset of start of i2c instruction memory */
|
||||||
|
uint32_t len; /* number of i2c instructions belonging to this i2c engine */
|
||||||
|
uint32_t clk_div; /* clock divider used by this i2c engine */
|
||||||
|
bool int_en;
|
||||||
|
i2c_inst_t i2c_inst[FPGA_I2C_NUM_INST];
|
||||||
|
} fpga_i2c_controller_t;
|
||||||
|
|
||||||
|
fpga_i2c_controller_t *fpga_i2c_ctrl_get(int bus_id);
|
||||||
|
void bf_fpga_reg_write(fpga_i2c_controller_t *i2c_ctrl,
|
||||||
|
uint32_t offset,
|
||||||
|
uint32_t val);
|
||||||
|
uint32_t bf_fpga_reg_read(fpga_i2c_controller_t *i2c_ctrl, uint32_t offset);
|
||||||
|
void bf_fpga_i2c_reg_write32(fpga_i2c_controller_t *i2c_ctrl,
|
||||||
|
uint32_t offset,
|
||||||
|
uint32_t val);
|
||||||
|
uint32_t bf_fpga_i2c_reg_read32(fpga_i2c_controller_t *i2c_ctrl,
|
||||||
|
uint32_t offset);
|
||||||
|
void bf_fpga_i2c_reg_write8(fpga_i2c_controller_t *i2c_ctrl,
|
||||||
|
uint32_t offset,
|
||||||
|
uint8_t val);
|
||||||
|
uint8_t bf_fpga_i2c_reg_read8(fpga_i2c_controller_t *i2c_ctrl, uint32_t offset);
|
||||||
|
|
||||||
|
int bf_fpga_i2c_lock(fpga_i2c_controller_t *i2c_ctrl);
|
||||||
|
|
||||||
|
void bf_fpga_i2c_unlock(fpga_i2c_controller_t *i2c_ctrl);
|
||||||
|
|
||||||
|
int fpga_i2c_start_locked(fpga_i2c_controller_t *i2c_ctrl);
|
||||||
|
int fpga_i2c_stop_locked(fpga_i2c_controller_t *i2c_ctrl);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* C++ */
|
||||||
|
|
||||||
|
#endif /* _BF_FPGA_I2C_PRIV_H */
|
@ -0,0 +1,93 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
Barefoot Networks FPGA Linux driver
|
||||||
|
Copyright(c) 2018 - 2019 Barefoot Networks, Inc.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it
|
||||||
|
under the terms and conditions of the GNU General Public License,
|
||||||
|
version 2, as published by the Free Software Foundation.
|
||||||
|
|
||||||
|
This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
The full GNU General Public License is included in this distribution in
|
||||||
|
the file called "COPYING".
|
||||||
|
|
||||||
|
Contact Information:
|
||||||
|
info@barefootnetworks.com
|
||||||
|
Barefoot Networks, 4750 Patrick Henry Drive, Santa Clara CA 95054
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
#ifndef _BF_FPGA_I2C_PRIV_PORTING_H
|
||||||
|
#define _BF_FPGA_I2C_PRIV_PORTING_H
|
||||||
|
|
||||||
|
/* Allow the use in C++ code. */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <linux/pci.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
|
||||||
|
/* This file contains OS and system specific porting functions declarations.
|
||||||
|
*/
|
||||||
|
/* return status compliant with linux system calls */
|
||||||
|
#define BF_FPGA_OK 0
|
||||||
|
#define BF_FPGA_EINVAL (-EINVAL)
|
||||||
|
#define BF_FPGA_EIO (-EIO)
|
||||||
|
#define BF_FPGA_EBUSY (-EBUSY)
|
||||||
|
#define BF_FPGA_EAGAIN (-EAGAIN)
|
||||||
|
|
||||||
|
/* pci memory access functions */
|
||||||
|
static inline void bf_fpga_write32(uint8_t *addr, uint32_t val) {
|
||||||
|
u8 __iomem *reg_addr = addr;
|
||||||
|
writel(val, reg_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t bf_fpga_read32(uint8_t *addr) {
|
||||||
|
u8 __iomem *reg_addr = addr;
|
||||||
|
return (readl(reg_addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void bf_fpga_write8(uint8_t *addr, uint8_t val) {
|
||||||
|
u8 __iomem *reg_addr = addr;
|
||||||
|
writeb(val, reg_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint8_t bf_fpga_read8(uint8_t *addr) {
|
||||||
|
u8 __iomem *reg_addr = addr;
|
||||||
|
return (readb(reg_addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void bf_fpga_us_delay(unsigned long usecs) {
|
||||||
|
usleep_range(usecs, usecs + 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* general purpose mutual exclusion lock */
|
||||||
|
typedef void *bf_fpga_mutex_t;
|
||||||
|
|
||||||
|
/* fast_lock for locking only non-blocking and quick operations */
|
||||||
|
typedef void *bf_fpga_fast_lock_t;
|
||||||
|
|
||||||
|
/* APIs to init/enter/leave critical (exclusive access) regions */
|
||||||
|
int bf_fpga_cr_init(bf_fpga_mutex_t *lock);
|
||||||
|
void bf_fpga_cr_destroy(bf_fpga_mutex_t *lock);
|
||||||
|
int bf_fpga_cr_enter(bf_fpga_mutex_t *lock);
|
||||||
|
void bf_fpga_cr_leave(bf_fpga_mutex_t *lock);
|
||||||
|
|
||||||
|
int bf_fpga_fast_lock_init(bf_fpga_fast_lock_t *sl, unsigned int initial);
|
||||||
|
void bf_fpga_fast_lock_destroy(bf_fpga_fast_lock_t *sl);
|
||||||
|
int bf_fpga_fast_lock(bf_fpga_fast_lock_t *sl);
|
||||||
|
void bf_fpga_fast_unlock(bf_fpga_fast_lock_t *sl);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* C++ */
|
||||||
|
|
||||||
|
#endif /* _BF_FPGA_I2C_PRIV_PORTING_H */
|
@ -0,0 +1,116 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
Barefoot Networks FPGA Linux driver
|
||||||
|
Copyright(c) 2018 - 2019 Barefoot Networks, Inc.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it
|
||||||
|
under the terms and conditions of the GNU General Public License,
|
||||||
|
version 2, as published by the Free Software Foundation.
|
||||||
|
|
||||||
|
This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
The full GNU General Public License is included in this distribution in
|
||||||
|
the file called "COPYING".
|
||||||
|
|
||||||
|
Contact Information:
|
||||||
|
info@barefootnetworks.com
|
||||||
|
Barefoot Networks, 4750 Patrick Henry Drive, Santa Clara CA 95054
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
#ifndef _BF_FPGA_I2C_REG_H
|
||||||
|
#define _BF_FPGA_I2C_REG_H
|
||||||
|
|
||||||
|
/* Allow the use in C++ code. */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* registers outsize of all i2c controller register space */
|
||||||
|
#define BF_FPGA_I2C_BASE_ADDR 0x0
|
||||||
|
#define BF_FPGA_I2C_CTRL_BASE_ADDR(i) (BF_FPGA_I2C_BASE_ADDR + (i * 4096))
|
||||||
|
|
||||||
|
/* per i2c controller register offset relative to BF_FPGA_I2C_CTRL_BASE_ADDR */
|
||||||
|
#define Bf_FPGA_I2C_CTRL_TOP 0
|
||||||
|
#define I2C_CTRL_START (1 << 0)
|
||||||
|
#define I2C_CTRL_RESET (1 << 1)
|
||||||
|
#define I2C_CTRL_CLK_DIV_SHF (8)
|
||||||
|
#define I2C_CTRL_CLK_DIV_MASK (0x1FF)
|
||||||
|
|
||||||
|
#define Bf_FPGA_TOP_I2C_STATUS 4
|
||||||
|
#define I2C_STS_BUSY (1 << 0)
|
||||||
|
#define I2C_STS_ERR (1 << 3)
|
||||||
|
|
||||||
|
#define Bf_FPGA_I2C_INST_CTRL(i) (0x10 + (16 * i))
|
||||||
|
#define I2C_INST_EN (1 << 31)
|
||||||
|
#define I2C_INST_PMT (1 << 30)
|
||||||
|
#define I2C_TYPE_SHF (26)
|
||||||
|
#define I2C_DELAY_SHF (23)
|
||||||
|
#define I2C_STOP_ON_ERROR (22)
|
||||||
|
/* various status values */
|
||||||
|
#define I2C_STATUS_MASK 0x3F
|
||||||
|
#define I2C_STATUS_ERR_MASK 0x3C
|
||||||
|
#define I2C_STATUS_RUNNING 0x1
|
||||||
|
#define I2C_STATUS_COMPLETED 0x2
|
||||||
|
#define I2C_STATUS_NACK_ADDR 0x4
|
||||||
|
#define I2C_STATUS_NACK_CMD 0x8
|
||||||
|
#define I2C_STATUS_NACK_WR_DATA 0x10
|
||||||
|
#define I2C_STATUS_TOUT 0x20
|
||||||
|
|
||||||
|
/* i2c instruction types */
|
||||||
|
#define I2C_WR_ADDR_DATA (0 << I2C_TYPE_SHF)
|
||||||
|
#define I2C_RD_DATA (3 << I2C_TYPE_SHF)
|
||||||
|
#define I2C_WR_ADDR (2 << I2C_TYPE_SHF)
|
||||||
|
#define I2C_RD_ADDR_DATA (1 << I2C_TYPE_SHF)
|
||||||
|
#define I2C_RD_ADDR_DATA_BURST (4 << I2C_TYPE_SHF)
|
||||||
|
#define I2C_NOP (6 << I2C_TYPE_SHF)
|
||||||
|
|
||||||
|
#define Bf_FPGA_I2C_INST_PARAM(i) (0x14 + (16 * i))
|
||||||
|
#define I2C_DEV_ADDR_SHF (24)
|
||||||
|
#define I2C_CMD_OFFSET (16)
|
||||||
|
#define I2C_WR_CNT_SHF (8)
|
||||||
|
#define I2C_RD_CNT_SHF (0)
|
||||||
|
|
||||||
|
#define Bf_FPGA_I2C_INST_DATA_LO(i) (0x18 + (16 * i))
|
||||||
|
#define Bf_FPGA_I2C_INST_DATA_HI(i) (0x1C + (16 * i))
|
||||||
|
/******************
|
||||||
|
#define Bf_FPGA_I2C_PR_CTRL(i) (0x100 + (16 * i))
|
||||||
|
#define Bf_FPGA_I2C_PR_PARM(i) (0x104 + (16 * i))
|
||||||
|
#define Bf_FPGA_I2C_PR_LO(i) (0x108 + (16 * i))
|
||||||
|
#define Bf_FPGA_I2C_PR_HI(i) (0x10C + (16 * i))
|
||||||
|
******************/
|
||||||
|
|
||||||
|
/* data area pointers */
|
||||||
|
/* the driver makes fixed static allocation of the available memory
|
||||||
|
* on per instruction basis
|
||||||
|
* allocate 128 bytes per one time instruction = total 0x780 bytes
|
||||||
|
* allocate 64 bytes per one periodic instruction = total 0x400 bytes
|
||||||
|
* FPGA_I2C_ONESHOT_NUM_INST -> comes from a header file that must be included
|
||||||
|
* before this file.
|
||||||
|
*/
|
||||||
|
#define BF_FPGA_ONE_MAX_BURST 128
|
||||||
|
#define BF_FPGA_PR_MAX_BURST 64
|
||||||
|
#define BF_FPGA_I2C_DATA_AREA(i) \
|
||||||
|
((i < FPGA_I2C_ONESHOT_NUM_INST) \
|
||||||
|
? (0x200 + (i * BF_FPGA_ONE_MAX_BURST)) \
|
||||||
|
: (0x980 + ((i - FPGA_I2C_ONESHOT_NUM_INST) * BF_FPGA_PR_MAX_BURST)))
|
||||||
|
|
||||||
|
#if BF_FPGA_I2C_DATA_AREA(FPGA_I2C_PERIODIC_NUM_INST) > 0x1000
|
||||||
|
#error erroneous allocation of FPGA memory to i2c data area. Fix it!
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define BF_FPGA_VER_REG 0x3F000
|
||||||
|
#define BF_FPGA_BUILD_DATE 0x3F004
|
||||||
|
#define BF_FPGA_RESET_CTRL_1 0x3F008
|
||||||
|
#define BF_FPGA_RESET_CTRL_2 0x3F00C
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* C++ */
|
||||||
|
|
||||||
|
#endif /* _BF_FPGA_I2C_REG_H */
|
10
platform/barefoot/sonic-platform-modules-bfn-newport/scripts/bf-sfputil
Executable file
10
platform/barefoot/sonic-platform-modules-bfn-newport/scripts/bf-sfputil
Executable file
@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
DOCKER_EXEC_FLAGS="i"
|
||||||
|
|
||||||
|
# Determine whether stdout is on a terminal
|
||||||
|
if [ -t 1 ] ; then
|
||||||
|
DOCKER_EXEC_FLAGS+="t"
|
||||||
|
fi
|
||||||
|
|
||||||
|
docker exec -$DOCKER_EXEC_FLAGS syncd sfputil "$@"
|
10
platform/barefoot/sonic-platform-modules-bfn-newport/scripts/eeprom
Executable file
10
platform/barefoot/sonic-platform-modules-bfn-newport/scripts/eeprom
Executable file
@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
DOCKER_EXEC_FLAGS="i"
|
||||||
|
|
||||||
|
# Determine whether stdout is on a terminal
|
||||||
|
if [ -t 1 ] ; then
|
||||||
|
DOCKER_EXEC_FLAGS+="t"
|
||||||
|
fi
|
||||||
|
|
||||||
|
docker exec -$DOCKER_EXEC_FLAGS syncd eeprom "$@"
|
11
platform/barefoot/sonic-platform-modules-bfn-newport/scripts/fancontrol
Executable file
11
platform/barefoot/sonic-platform-modules-bfn-newport/scripts/fancontrol
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
DOCKER_EXEC_FLAGS="i"
|
||||||
|
|
||||||
|
# Determine whether stdout is on a terminal
|
||||||
|
if [ -t 1 ] ; then
|
||||||
|
DOCKER_EXEC_FLAGS+="t"
|
||||||
|
fi
|
||||||
|
|
||||||
|
docker exec -$DOCKER_EXEC_FLAGS syncd fancontrol "$@"
|
||||||
|
|
10
platform/barefoot/sonic-platform-modules-bfn-newport/scripts/ps_info
Executable file
10
platform/barefoot/sonic-platform-modules-bfn-newport/scripts/ps_info
Executable file
@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
DOCKER_EXEC_FLAGS="i"
|
||||||
|
|
||||||
|
# Determine whether stdout is on a terminal
|
||||||
|
if [ -t 1 ] ; then
|
||||||
|
DOCKER_EXEC_FLAGS+="t"
|
||||||
|
fi
|
||||||
|
|
||||||
|
docker exec -$DOCKER_EXEC_FLAGS syncd ps_info "$@"
|
12
platform/barefoot/sonic-platform-modules-bfn-newport/scripts/sensors
Executable file
12
platform/barefoot/sonic-platform-modules-bfn-newport/scripts/sensors
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
DOCKER_EXEC_FLAGS="i"
|
||||||
|
|
||||||
|
# Determine whether stdout is on a terminal
|
||||||
|
if [ -t 1 ] ; then
|
||||||
|
DOCKER_EXEC_FLAGS+="t"
|
||||||
|
fi
|
||||||
|
|
||||||
|
docker exec -$DOCKER_EXEC_FLAGS syncd sensors "$@"
|
||||||
|
|
||||||
|
|
1
platform/barefoot/sonic-platform-modules-bfn-newport/scripts/test
Executable file
1
platform/barefoot/sonic-platform-modules-bfn-newport/scripts/test
Executable file
@ -0,0 +1 @@
|
|||||||
|
echo "test"
|
Loading…
Reference in New Issue
Block a user