Skip to content
Merged
2 changes: 1 addition & 1 deletion platform/pddf/i2c/debian/rules
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ PACKAGE_PRE_NAME := sonic-platform-pddf
KVERSION ?= $(shell uname -r)
KERNEL_SRC := /lib/modules/$(KVERSION)
MOD_SRC_DIR:= $(shell pwd)
MODULE_DIRS:= client cpld cpld/driver cpldmux cpldmux/driver fpgai2c fpgai2c/driver fpgapci fpgapci/driver fpgapci/algos fan fan/driver mux gpio led psu psu/driver sysstatus xcvr xcvr/driver
MODULE_DIRS:= client cpld cpld/driver cpldmux cpldmux/driver fpgai2c fpgai2c/driver fpgapci fpgapci/driver fpgapci/algos multifpgapci multifpgapci/driver multifpgapci/i2c fan fan/driver mux gpio led psu psu/driver sysstatus xcvr xcvr/driver
MODULE_DIR:= modules
UTILS_DIR := utils
SERVICE_DIR := service
Expand Down
2 changes: 1 addition & 1 deletion platform/pddf/i2c/modules/Makefile
Original file line number Diff line number Diff line change
@@ -1 +1 @@
obj-m := client/ cpld/ cpldmux/ fpgai2c/ fpgapci/ xcvr/ mux/ gpio/ psu/ fan/ led/ sysstatus/
obj-m := client/ cpld/ cpldmux/ fpgai2c/ fpgapci/ multifpgapci/ xcvr/ mux/ gpio/ psu/ fan/ led/ sysstatus/
69 changes: 63 additions & 6 deletions platform/pddf/i2c/modules/cpldmux/driver/pddf_cpldmux_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <linux/platform_device.h>
#include "pddf_client_defs.h"
#include "pddf_cpldmux_defs.h"
#include "pddf_multifpgapci_defs.h"

extern PDDF_CPLDMUX_DATA pddf_cpldmux_data;

Expand Down Expand Up @@ -94,14 +95,39 @@ int pddf_cpldmux_select_default(struct i2c_mux_core *muxc, uint32_t chan)
return 0;
}

if ( (pdata->chan_cache!=1) || (private->last_chan!=chan) )
{
if ((pdata->chan_cache != 1) || (private->last_chan != chan)) {
sdata = &pdata->chan_data[chan];
pddf_dbg(CPLDMUX, KERN_INFO "%s: Writing 0x%x at 0x%x offset of cpld 0x%x to enable chan %d\n", __FUNCTION__, sdata->cpld_sel, sdata->cpld_offset, sdata->cpld_devaddr, chan);
ret = cpldmux_byte_write(pdata->cpld, sdata->cpld_offset, (uint8_t)(sdata->cpld_sel & 0xff));
switch (pdata->dev_type) {
case CPLD_MUX:
// cpld_mux
pddf_dbg(
CPLDMUX,
KERN_INFO
"%s: Writing 0x%x at 0x%x offset of cpld 0x%x to enable chan %d\n",
__FUNCTION__, sdata->cpld_sel,
sdata->cpld_offset, sdata->cpld_devaddr, chan);
ret = cpldmux_byte_write(
pdata->cpld, sdata->cpld_offset,
(uint8_t)(sdata->cpld_sel & 0xff));
break;
case MULTIFPGAPCI_MUX:
ret = ptr_multifpgapci_writepci(
pdata->fpga_pci_dev,
sdata->cpld_sel,
sdata->cpld_offset);
break;
default:
printk(KERN_ERR "%s: Unexpected device type %d\n",
__FUNCTION__, pdata->dev_type);
break;
}
private->last_chan = chan;
}

if (ret) {
printk(KERN_ERR "%s: Error status = %d", __FUNCTION__, ret);
}

return ret;
}

Expand All @@ -120,9 +146,33 @@ int pddf_cpldmux_deselect_default(struct i2c_mux_core *muxc, uint32_t chan)
return 0;
}
sdata = &pdata->chan_data[chan];
switch (pdata->dev_type) {
case CPLD_MUX:
pddf_dbg(
CPLDMUX,
KERN_INFO
"%s: Writing 0x%x at 0x%x offset of cpld 0x%x to disable chan %d",
__FUNCTION__, sdata->cpld_desel, sdata->cpld_offset,
sdata->cpld_devaddr, chan);
ret = cpldmux_byte_write(pdata->cpld, sdata->cpld_offset,
(uint8_t)(sdata->cpld_desel));
break;
case MULTIFPGAPCI_MUX:
ret = ptr_multifpgapci_writepci(
pdata->fpga_pci_dev,
sdata->cpld_desel,
sdata->cpld_offset);
break;
default:
printk(KERN_ERR "%s: Unexpected device type %d\n", __FUNCTION__,
pdata->dev_type);
break;
}

if (ret) {
printk(KERN_ERR "%s: Error status = %d", __FUNCTION__, ret);
}

pddf_dbg(CPLDMUX, KERN_INFO "%s: Writing 0x%x at 0x%x offset of cpld 0x%x to disable chan %d", __FUNCTION__, sdata->cpld_desel, sdata->cpld_offset, sdata->cpld_devaddr, chan);
ret = cpldmux_byte_write(pdata->cpld, sdata->cpld_offset, (uint8_t)(sdata->cpld_desel));
return ret;
}

Expand Down Expand Up @@ -204,13 +254,20 @@ static int cpld_mux_remove(struct platform_device *pdev)
return 0;
}

static const struct platform_device_id mux_ids[] = {
{ "cpld_mux", 0 },
{ "multifpgapci_mux", 0 },
{},
};

static struct platform_driver cpld_mux_driver = {
.probe = cpld_mux_probe,
.remove = cpld_mux_remove, /* TODO */
.driver = {
.owner = THIS_MODULE,
.name = "cpld_mux",
},
.id_table = mux_ids,
};

static int __init board_i2c_cpldmux_init(void)
Expand Down
138 changes: 92 additions & 46 deletions platform/pddf/i2c/modules/cpldmux/pddf_cpldmux_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/kobject.h>
#include "pddf_client_defs.h"
Expand Down Expand Up @@ -58,7 +59,6 @@ PDDF_DATA_ATTR(cpld_offset, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PD
PDDF_DATA_ATTR(cpld_sel, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_HEX, sizeof(int), (void*)&pddf_cpldmux_chan_data.cpld_sel, NULL);
PDDF_DATA_ATTR(cpld_desel, S_IWUSR|S_IRUGO, show_pddf_data, store_pddf_data, PDDF_INT_HEX, sizeof(int), (void*)&pddf_cpldmux_chan_data.cpld_desel, NULL);


static struct attribute *cpldmux_attributes[] = {
&attr_dev_ops.dev_attr.attr,
&attr_chan_ops.dev_attr.attr,
Expand Down Expand Up @@ -104,56 +104,101 @@ static ssize_t do_device_operation(struct device *dev, struct device_attribute *
PDDF_CPLDMUX_DATA *cpldmux_data = (PDDF_CPLDMUX_DATA *)(ptr->addr);
PDDF_CPLDMUX_PDATA *cpldmux_platform_data = NULL;
struct platform_device *plat_dev = NULL;
struct i2c_client *client_ptr = NULL;
struct i2c_client *client_ptr = NULL;
struct pci_dev *pci_dev = NULL;
int ret=0, i=0;

if (strncmp(buf, "add", strlen(buf)-1)==0)
{
if (strncmp(device_ptr->dev_type, "cpld_mux", strlen("cpld_mux"))==0)
{
/*Get the i2c_client handle for the CPLD which drives this cpldmux*/
client_ptr = (struct i2c_client *)get_device_table(cpldmux_data->cpld_name);
if (client_ptr==NULL)
{
pddf_dbg(CPLDMUX, KERN_ERR "Unable to get the CPLD client %s for %s cpldmux\n", cpldmux_data->cpld_name, device_ptr->i2c_name);
printk(KERN_ERR "Unable to get the CPLD client %s for %s cpldmux\n", cpldmux_data->cpld_name, device_ptr->i2c_name);
goto clear_data;
}

/* Allocate the cpldmux_platform_data */
cpldmux_platform_data = (PDDF_CPLDMUX_PDATA *)kzalloc( sizeof(PDDF_CPLDMUX_PDATA) + cpldmux_data->num_chan*sizeof(PDDF_CPLDMUX_CHAN_DATA), GFP_KERNEL );
cpldmux_platform_data->chan_data = (PDDF_CPLDMUX_CHAN_DATA *)(cpldmux_platform_data+1);

cpldmux_platform_data->parent_bus = device_ptr->parent_bus;
cpldmux_platform_data->base_chan = cpldmux_data->base_chan;
cpldmux_platform_data->num_chan = cpldmux_data->num_chan;
cpldmux_platform_data->chan_cache = cpldmux_data->chan_cache;
cpldmux_platform_data->cpld = client_ptr;
for (i=0; i<cpldmux_data->num_chan; i++)
{
cpldmux_platform_data->chan_data[i] = cpldmux_data->chan_data[i];
}

plat_dev = platform_device_alloc(device_ptr->dev_type, device_ptr->dev_id);

plat_dev->dev.platform_data = cpldmux_platform_data;

pddf_dbg(CPLDMUX, KERN_ERR "Creating a %s platform_device 0x%p, platform_data 0x%p\n", plat_dev->name, (void *)plat_dev, (void *)cpldmux_platform_data);
ret = platform_device_add(plat_dev);
if (ret)
{
pddf_dbg(CPLDMUX, KERN_ERR "Unable to create cpld_mux (%s) device: Error %d\n", device_ptr->i2c_name, ret);
goto free_data;
}
else
{
add_device_table(device_ptr->i2c_name, (void *)plat_dev);
}
/* Allocate the cpldmux_platform_data */
cpldmux_platform_data = (PDDF_CPLDMUX_PDATA *)kzalloc(
sizeof(PDDF_CPLDMUX_PDATA) +
cpldmux_data->num_chan *
sizeof(PDDF_CPLDMUX_CHAN_DATA),
GFP_KERNEL);
if (!cpldmux_platform_data) {
printk("%s(%d): kzalloc failure.\n", __func__,
__LINE__);
goto clear_data;
}
cpldmux_platform_data->chan_data =
(PDDF_CPLDMUX_CHAN_DATA *)(cpldmux_platform_data + 1);

cpldmux_platform_data->parent_bus = device_ptr->parent_bus;
cpldmux_platform_data->base_chan = cpldmux_data->base_chan;
cpldmux_platform_data->num_chan = cpldmux_data->num_chan;
cpldmux_platform_data->chan_cache = cpldmux_data->chan_cache;
for (i = 0; i < cpldmux_data->num_chan; i++) {
cpldmux_platform_data->chan_data[i] =
cpldmux_data->chan_data[i];
}

plat_dev = platform_device_alloc(device_ptr->dev_type,
device_ptr->dev_id);
if (!plat_dev) {
printk("%s(%d): platform_device_alloc failure.\n",
__func__, __LINE__);
goto free_data;
}
else
{
printk(KERN_ERR "%s: Unsupported type of cpldmux - unable to add i2c client\n", __FUNCTION__);

plat_dev->dev.platform_data = cpldmux_platform_data;
if (strncmp(device_ptr->dev_type, "cpld_mux",
strlen("cpld_mux")) == 0) {
cpldmux_platform_data->dev_type = CPLD_MUX;
/*Get the i2c_client handle for the CPLD which drives this cpldmux*/
client_ptr = (struct i2c_client *)get_device_table(
cpldmux_data->cpld_name);
if (client_ptr == NULL) {
pddf_dbg(
CPLDMUX,
KERN_ERR
"Unable to get the CPLD client %s for %s cpldmux\n",
cpldmux_data->cpld_name,
device_ptr->i2c_name);
printk(KERN_ERR
"Unable to get the CPLD client %s for %s cpldmux\n",
cpldmux_data->cpld_name,
device_ptr->i2c_name);
goto free_data;
}
cpldmux_platform_data->cpld = client_ptr;
} else if (strncmp(device_ptr->dev_type, "multifpgapci_mux",
strlen("multifpgapci_mux")) == 0) {
cpldmux_platform_data->dev_type = MULTIFPGAPCI_MUX;
pci_dev = (struct pci_dev *)get_device_table(
cpldmux_data->cpld_name
);
if (pci_dev == NULL) {
printk(KERN_ERR
"PDDF_CPLDMUX: Unable to get pci_dev of %s for %s\n",
cpldmux_data->cpld_name,
device_ptr->i2c_name);
goto free_data;
}
cpldmux_platform_data->fpga_pci_dev = pci_dev_get(pci_dev);
} else {
printk(KERN_ERR
"%s: Unsupported type of cpldmux - unable to add i2c client\n",
__FUNCTION__);
goto free_data;
}
pddf_dbg(
CPLDMUX,
KERN_ERR
"Creating a %s platform_device 0x%p, platform_data 0x%p\n",
plat_dev->name, (void *)plat_dev,
(void *)cpldmux_platform_data);
ret = platform_device_add(plat_dev);
if (ret) {
pddf_dbg(
CPLDMUX,
KERN_ERR
"Unable to create cpld_mux (%s) device: Error %d\n",
device_ptr->i2c_name, ret);
goto free_data;
} else {
add_device_table(device_ptr->i2c_name,
(void *)plat_dev);
}
}
else if (strncmp(buf, "delete", strlen(buf)-1)==0)
Expand All @@ -163,7 +208,8 @@ static ssize_t do_device_operation(struct device *dev, struct device_attribute *
if (plat_dev)
{
pddf_dbg(CPLDMUX, KERN_ERR "Removing %s device: 0x%p\n", device_ptr->i2c_name, (void *)plat_dev);
pddf_dbg(CPLDMUX, KERN_ERR "Freeing the memory held by device: 0x%p\n", (void *)plat_dev);
pddf_dbg(CPLDMUX, KERN_ERR "Freeing the memory held by device: 0x%p\n", (void *)plat_dev);
pci_dev_put(((PDDF_CPLDMUX_PDATA *)plat_dev->dev.platform_data)->fpga_pci_dev);
platform_device_del(plat_dev);
delete_device_table(device_ptr->i2c_name);
}
Expand Down
1 change: 1 addition & 0 deletions platform/pddf/i2c/modules/include/pddf_client_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#define SYSSTATUS "PDDF_SYSSTATUS"
#define XCVR "PDDF_XCVR"
#define FPGA "PDDF_FPGAPCI"
#define MULTIFPGA "PDDF_MULTIFPGAPCI"


#define PDDF_DEBUG
Expand Down
9 changes: 9 additions & 0 deletions platform/pddf/i2c/modules/include/pddf_cpldmux_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,22 @@ typedef struct CPLDMUX_DATA
PDDF_CPLDMUX_CHAN_DATA chan_data[MAX_CPLDMUX_CHAN];
}PDDF_CPLDMUX_DATA;

typedef enum
{
CPLD_MUX,
MULTIFPGAPCI_MUX,
}PDDF_CPLDMUX_DEV_TYPE;

typedef struct CPLDMUX_PDATA
{
int parent_bus;
int base_chan;
int num_chan;
int chan_cache;
PDDF_CPLDMUX_DEV_TYPE dev_type;
struct i2c_client *cpld;
struct pci_dev
*fpga_pci_dev; // identifies the FPGA when dev_type is MULTIFPGAPCI_MUX
PDDF_CPLDMUX_CHAN_DATA *chan_data;
}PDDF_CPLDMUX_PDATA;

Expand Down
2 changes: 1 addition & 1 deletion platform/pddf/i2c/modules/include/pddf_i2c_algo.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#include "pddf_client_defs.h"

/* max number of adapters */
#define I2C_PCI_MAX_BUS 16
#define I2C_PCI_MAX_BUS 512

/**
* struct fpgapci_devdata - PCI device data structure
Expand Down
57 changes: 57 additions & 0 deletions platform/pddf/i2c/modules/include/pddf_multifpgapci_defs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright 2025 Nexthop Systems 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.
*
* Description:
* Platform MULTIFPGAPCI defines/structures header file
*/

#ifndef __PDDF_MULTIFPGAPCI_DEFS_H__
#define __PDDF_MULTIFPGAPCI_DEFS_H__

#include "linux/types.h"
#include <linux/pci.h>

#include "pddf_multifpgapci_i2c_defs.h"

#define NAME_SIZE 32
#define KOBJ_FREE(obj) \
if (obj) \
kobject_put(obj);

struct pddf_multifpgapci_drvdata {
struct pci_dev *pci_dev;
resource_size_t bar_start;
void *__iomem fpga_data_base_addr;
// i2c
size_t bar_length;
struct kobject *i2c_kobj;
struct i2c_adapter_drvdata i2c_adapter_drvdata;
bool i2c_adapter_drvdata_initialized;
};

// FPGA
typedef struct {
uint32_t data_base_offset;
uint32_t data_size;
} FPGA_OPS_DATA;

struct pddf_multi_fpgapci_ops_t {
int (*post_device_operation)(struct pci_dev *);
};

extern struct pddf_multi_fpgapci_ops_t pddf_multi_fpgapci_ops;

extern int (*ptr_multifpgapci_readpci)(struct pci_dev *, uint32_t, uint32_t *);
extern int (*ptr_multifpgapci_writepci)(struct pci_dev *, uint32_t, uint32_t);

#endif
Loading
Loading