Commit ce7ec1b8 authored by David S. Miller's avatar David S. Miller

Merge branch 'ptrp-ocp-next'

Jonathan Lemon says:

====================
ptp: ocp: update devlink information

Both of these patches update the information displayed via devlink.

v1 -> v2: remove board.manufacture information
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents b57b44f7 b0ca789a
......@@ -11,12 +11,14 @@
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/platform_device.h>
#include <linux/platform_data/i2c-xiic.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/spi/spi.h>
#include <linux/spi/xilinx_spi.h>
#include <net/devlink.h>
#include <linux/i2c.h>
#include <linux/mtd/mtd.h>
#include <linux/nvmem-consumer.h>
#ifndef PCI_VENDOR_ID_FACEBOOK
#define PCI_VENDOR_ID_FACEBOOK 0x1d9b
......@@ -204,6 +206,9 @@ struct ptp_ocp_ext_src {
int irq_vec;
};
#define OCP_BOARD_ID_LEN 13
#define OCP_SERIAL_LEN 6
struct ptp_ocp {
struct pci_dev *pdev;
struct device dev;
......@@ -230,6 +235,7 @@ struct ptp_ocp {
struct platform_device *spi_flash;
struct clk_hw *i2c_clk;
struct timer_list watchdog;
const struct ptp_ocp_eeprom_map *eeprom_map;
struct dentry *debug_root;
time64_t gnss_lost;
int id;
......@@ -238,8 +244,10 @@ struct ptp_ocp {
int gnss2_port;
int mac_port; /* miniature atomic clock */
int nmea_port;
u8 serial[6];
bool has_serial;
u32 fw_version;
u8 board_id[OCP_BOARD_ID_LEN];
u8 serial[OCP_SERIAL_LEN];
bool has_eeprom_data;
u32 pps_req_map;
int flash_start;
u32 utc_tai_offset;
......@@ -268,6 +276,28 @@ static int ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r);
static irqreturn_t ptp_ocp_ts_irq(int irq, void *priv);
static int ptp_ocp_ts_enable(void *priv, u32 req, bool enable);
struct ptp_ocp_eeprom_map {
u16 off;
u16 len;
u32 bp_offset;
const void * const tag;
};
#define EEPROM_ENTRY(addr, member) \
.off = addr, \
.len = sizeof_field(struct ptp_ocp, member), \
.bp_offset = offsetof(struct ptp_ocp, member)
#define BP_MAP_ENTRY_ADDR(bp, map) ({ \
(void *)((uintptr_t)(bp) + (map)->bp_offset); \
})
static struct ptp_ocp_eeprom_map fb_eeprom_map[] = {
{ EEPROM_ENTRY(0x43, board_id) },
{ EEPROM_ENTRY(0x00, serial), .tag = "mac" },
{ }
};
#define bp_assign_entry(bp, res, val) ({ \
uintptr_t addr = (uintptr_t)(bp) + (res)->bp_offset; \
*(typeof(val) *)addr = val; \
......@@ -396,6 +426,15 @@ static struct ocp_resource ocp_fb_resource[] = {
.extra = &(struct ptp_ocp_i2c_info) {
.name = "xiic-i2c",
.fixed_rate = 50000000,
.data_size = sizeof(struct xiic_i2c_platform_data),
.data = &(struct xiic_i2c_platform_data) {
.num_devices = 2,
.devices = (struct i2c_board_info[]) {
{ I2C_BOARD_INFO("24c02", 0x50) },
{ I2C_BOARD_INFO("24mac402", 0x58),
.platform_data = "mac" },
},
},
},
},
{
......@@ -919,78 +958,88 @@ ptp_ocp_tod_gnss_name(int idx)
return gnss_name[idx];
}
struct ptp_ocp_nvmem_match_info {
struct ptp_ocp *bp;
const void * const tag;
};
static int
ptp_ocp_firstchild(struct device *dev, void *data)
ptp_ocp_nvmem_match(struct device *dev, const void *data)
{
return 1;
const struct ptp_ocp_nvmem_match_info *info = data;
dev = dev->parent;
if (!i2c_verify_client(dev) || info->tag != dev->platform_data)
return 0;
while ((dev = dev->parent))
if (dev->driver && !strcmp(dev->driver->name, KBUILD_MODNAME))
return info->bp == dev_get_drvdata(dev);
return 0;
}
static int
ptp_ocp_read_i2c(struct i2c_adapter *adap, u8 addr, u8 reg, u8 sz, u8 *data)
static inline struct nvmem_device *
ptp_ocp_nvmem_device_get(struct ptp_ocp *bp, const void * const tag)
{
struct i2c_msg msgs[2] = {
{
.addr = addr,
.len = 1,
.buf = &reg,
},
{
.addr = addr,
.flags = I2C_M_RD,
.len = 2,
.buf = data,
},
};
int err;
u8 len;
/* xiic-i2c for some stupid reason only does 2 byte reads. */
while (sz) {
len = min_t(u8, sz, 2);
msgs[1].len = len;
err = i2c_transfer(adap, msgs, 2);
if (err != msgs[1].len)
return err;
msgs[1].buf += len;
reg += len;
sz -= len;
struct ptp_ocp_nvmem_match_info info = { .bp = bp, .tag = tag };
return nvmem_device_find(&info, ptp_ocp_nvmem_match);
}
static inline void
ptp_ocp_nvmem_device_put(struct nvmem_device **nvmemp)
{
if (*nvmemp != NULL) {
nvmem_device_put(*nvmemp);
*nvmemp = NULL;
}
return 0;
}
static void
ptp_ocp_get_serial_number(struct ptp_ocp *bp)
ptp_ocp_read_eeprom(struct ptp_ocp *bp)
{
struct i2c_adapter *adap;
struct device *dev;
int err;
const struct ptp_ocp_eeprom_map *map;
struct nvmem_device *nvmem;
const void *tag;
int ret;
if (!bp->i2c_ctrl)
return;
dev = device_find_child(&bp->i2c_ctrl->dev, NULL, ptp_ocp_firstchild);
if (!dev) {
dev_err(&bp->pdev->dev, "Can't find I2C adapter\n");
return;
}
tag = NULL;
nvmem = NULL;
adap = i2c_verify_adapter(dev);
if (!adap) {
dev_err(&bp->pdev->dev, "device '%s' isn't an I2C adapter\n",
dev_name(dev));
goto out;
}
err = ptp_ocp_read_i2c(adap, 0x58, 0x9A, 6, bp->serial);
if (err) {
dev_err(&bp->pdev->dev, "could not read eeprom: %d\n", err);
goto out;
for (map = bp->eeprom_map; map->len; map++) {
if (map->tag != tag) {
tag = map->tag;
ptp_ocp_nvmem_device_put(&nvmem);
}
if (!nvmem) {
nvmem = ptp_ocp_nvmem_device_get(bp, tag);
if (!nvmem)
goto out;
}
ret = nvmem_device_read(nvmem, map->off, map->len,
BP_MAP_ENTRY_ADDR(bp, map));
if (ret != map->len)
goto read_fail;
}
bp->has_serial = true;
bp->has_eeprom_data = true;
out:
put_device(dev);
ptp_ocp_nvmem_device_put(&nvmem);
return;
read_fail:
dev_err(&bp->pdev->dev, "could not read eeprom: %d\n", ret);
goto out;
}
static int
ptp_ocp_firstchild(struct device *dev, void *data)
{
return 1;
}
static struct device *
......@@ -1091,34 +1140,33 @@ ptp_ocp_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
if (err)
return err;
if (bp->image) {
u32 ver = ioread32(&bp->image->version);
if (ver & 0xffff) {
sprintf(buf, "%d", ver);
err = devlink_info_version_running_put(req,
"fw",
buf);
} else {
sprintf(buf, "%d", ver >> 16);
err = devlink_info_version_running_put(req,
"loader",
buf);
}
if (err)
return err;
if (bp->fw_version & 0xffff) {
sprintf(buf, "%d", bp->fw_version);
err = devlink_info_version_running_put(req, "fw", buf);
} else {
sprintf(buf, "%d", bp->fw_version >> 16);
err = devlink_info_version_running_put(req, "loader", buf);
}
if (err)
return err;
if (!bp->has_serial)
ptp_ocp_get_serial_number(bp);
if (bp->has_serial) {
sprintf(buf, "%pM", bp->serial);
err = devlink_info_serial_number_put(req, buf);
if (err)
return err;
if (!bp->has_eeprom_data) {
ptp_ocp_read_eeprom(bp);
if (!bp->has_eeprom_data)
return 0;
}
sprintf(buf, "%pM", bp->serial);
err = devlink_info_serial_number_put(req, buf);
if (err)
return err;
err = devlink_info_version_fixed_put(req,
DEVLINK_INFO_VERSION_GENERIC_BOARD_ID,
bp->board_id);
if (err)
return err;
return 0;
}
......@@ -1412,6 +1460,8 @@ static int
ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
{
bp->flash_start = 1024 * 4096;
bp->eeprom_map = fb_eeprom_map;
bp->fw_version = ioread32(&bp->image->version);
ptp_ocp_tod_init(bp);
ptp_ocp_nmea_out_init(bp);
......@@ -1810,8 +1860,8 @@ serialnum_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct ptp_ocp *bp = dev_get_drvdata(dev);
if (!bp->has_serial)
ptp_ocp_get_serial_number(bp);
if (!bp->has_eeprom_data)
ptp_ocp_read_eeprom(bp);
return sysfs_emit(buf, "%pM\n", bp->serial);
}
......@@ -2520,17 +2570,14 @@ ptp_ocp_info(struct ptp_ocp *bp)
ptp_ocp_phc_info(bp);
if (bp->image) {
u32 ver = ioread32(&bp->image->version);
dev_info(dev, "version %x\n", bp->fw_version);
if (bp->fw_version & 0xffff)
dev_info(dev, "regular image, version %d\n",
bp->fw_version & 0xffff);
else
dev_info(dev, "golden image, version %d\n",
bp->fw_version >> 16);
dev_info(dev, "version %x\n", ver);
if (ver & 0xffff)
dev_info(dev, "regular image, version %d\n",
ver & 0xffff);
else
dev_info(dev, "golden image, version %d\n",
ver >> 16);
}
ptp_ocp_serial_info(dev, "GNSS", bp->gnss_port, 115200);
ptp_ocp_serial_info(dev, "GNSS2", bp->gnss2_port, 115200);
ptp_ocp_serial_info(dev, "MAC", bp->mac_port, 57600);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment