Commit 57d7becd authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'ptp-ocp-various-updates'

Jonathan Lemon says:

====================
ptp: ocp: various updates

Collection of cleanups and updates to the timecard.
====================

Link: https://lore.kernel.org/r/20220519212153.450437-1-jonathan.lemon@gmail.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 9029ac03 3c3673bd
Loading
Loading
Loading
Loading
+348 −211
Original line number Diff line number Diff line
@@ -19,14 +19,13 @@
#include <linux/i2c.h>
#include <linux/mtd/mtd.h>
#include <linux/nvmem-consumer.h>
#include <linux/crc16.h>

#ifndef PCI_VENDOR_ID_FACEBOOK
#define PCI_VENDOR_ID_FACEBOOK			0x1d9b
#endif

#ifndef PCI_DEVICE_ID_FACEBOOK_TIMECARD
#define PCI_DEVICE_ID_FACEBOOK_TIMECARD		0x0400
#endif

#define PCI_VENDOR_ID_CELESTICA			0x18d4
#define PCI_DEVICE_ID_CELESTICA_TIMECARD	0x1008

static struct class timecard_class = {
	.owner		= THIS_MODULE,
@@ -215,6 +214,17 @@ struct ptp_ocp_flash_info {
	void *data;
};

struct ptp_ocp_firmware_header {
	char magic[4];
	__be16 pci_vendor_id;
	__be16 pci_device_id;
	__be32 image_size;
	__be16 hw_revision;
	__be16 crc;
};

#define OCP_FIRMWARE_MAGIC_HEADER "OCPC"

struct ptp_ocp_i2c_info {
	const char *name;
	unsigned long fixed_rate;
@@ -245,6 +255,7 @@ struct ptp_ocp_sma_connector {
	bool	fixed_fcn;
	bool	fixed_dir;
	bool	disabled;
	u8	default_fcn;
};

struct ocp_attr_group {
@@ -310,7 +321,9 @@ struct ptp_ocp {
	int			gnss2_port;
	int			mac_port;	/* miniature atomic clock */
	int			nmea_port;
	u32			fw_version;
	bool			fw_loader;
	u8			fw_tag;
	u16			fw_version;
	u8			board_id[OCP_BOARD_ID_LEN];
	u8			serial[OCP_SERIAL_LEN];
	bool			has_eeprom_data;
@@ -321,6 +334,7 @@ struct ptp_ocp {
	u64			fw_cap;
	struct ptp_ocp_signal	signal[4];
	struct ptp_ocp_sma_connector sma[4];
	const struct ocp_sma_op *sma_op;
};

#define OCP_REQ_TIMESTAMP	BIT(0)
@@ -634,7 +648,8 @@ static struct ocp_resource ocp_fb_resource[] = {

static const struct pci_device_id ptp_ocp_pcidev_id[] = {
	{ PCI_DEVICE_DATA(FACEBOOK, TIMECARD, &ocp_fb_resource) },
	{ 0 }
	{ PCI_DEVICE_DATA(CELESTICA, TIMECARD, &ocp_fb_resource) },
	{ }
};
MODULE_DEVICE_TABLE(pci, ptp_ocp_pcidev_id);

@@ -646,7 +661,7 @@ struct ocp_selector {
	int value;
};

static struct ocp_selector ptp_ocp_clock[] = {
static const struct ocp_selector ptp_ocp_clock[] = {
	{ .name = "NONE",	.value = 0 },
	{ .name = "TOD",	.value = 1 },
	{ .name = "IRIG",	.value = 2 },
@@ -663,7 +678,7 @@ static struct ocp_selector ptp_ocp_clock[] = {
#define SMA_SELECT_MASK		((1U << 15) - 1)
#define SMA_DISABLE		0x10000

static struct ocp_selector ptp_ocp_sma_in[] = {
static const struct ocp_selector ptp_ocp_sma_in[] = {
	{ .name = "10Mhz",	.value = 0x0000 },
	{ .name = "PPS1",	.value = 0x0001 },
	{ .name = "PPS2",	.value = 0x0002 },
@@ -681,7 +696,7 @@ static struct ocp_selector ptp_ocp_sma_in[] = {
	{ }
};

static struct ocp_selector ptp_ocp_sma_out[] = {
static const struct ocp_selector ptp_ocp_sma_out[] = {
	{ .name = "10Mhz",	.value = 0x0000 },
	{ .name = "PHC",	.value = 0x0001 },
	{ .name = "MAC",	.value = 0x0002 },
@@ -698,8 +713,40 @@ static struct ocp_selector ptp_ocp_sma_out[] = {
	{ }
};

struct ocp_sma_op {
	const struct ocp_selector *tbl[2];
	void (*init)(struct ptp_ocp *bp);
	u32 (*get)(struct ptp_ocp *bp, int sma_nr);
	int (*set_inputs)(struct ptp_ocp *bp, int sma_nr, u32 val);
	int (*set_output)(struct ptp_ocp *bp, int sma_nr, u32 val);
};

static void
ptp_ocp_sma_init(struct ptp_ocp *bp)
{
	return bp->sma_op->init(bp);
}

static u32
ptp_ocp_sma_get(struct ptp_ocp *bp, int sma_nr)
{
	return bp->sma_op->get(bp, sma_nr);
}

static int
ptp_ocp_sma_set_inputs(struct ptp_ocp *bp, int sma_nr, u32 val)
{
	return bp->sma_op->set_inputs(bp, sma_nr, val);
}

static int
ptp_ocp_sma_set_output(struct ptp_ocp *bp, int sma_nr, u32 val)
{
	return bp->sma_op->set_output(bp, sma_nr, val);
}

static const char *
ptp_ocp_select_name_from_val(struct ocp_selector *tbl, int val)
ptp_ocp_select_name_from_val(const struct ocp_selector *tbl, int val)
{
	int i;

@@ -710,7 +757,7 @@ ptp_ocp_select_name_from_val(struct ocp_selector *tbl, int val)
}

static int
ptp_ocp_select_val_from_name(struct ocp_selector *tbl, const char *name)
ptp_ocp_select_val_from_name(const struct ocp_selector *tbl, const char *name)
{
	const char *select;
	int i;
@@ -724,7 +771,7 @@ ptp_ocp_select_val_from_name(struct ocp_selector *tbl, const char *name)
}

static ssize_t
ptp_ocp_select_table_show(struct ocp_selector *tbl, char *buf)
ptp_ocp_select_table_show(const struct ocp_selector *tbl, char *buf)
{
	ssize_t count;
	int i;
@@ -1288,25 +1335,81 @@ ptp_ocp_find_flash(struct ptp_ocp *bp)
	return dev;
}

static int
ptp_ocp_devlink_fw_image(struct devlink *devlink, const struct firmware *fw,
			 const u8 **data, size_t *size)
{
	struct ptp_ocp *bp = devlink_priv(devlink);
	const struct ptp_ocp_firmware_header *hdr;
	size_t offset, length;
	u16 crc;

	hdr = (const struct ptp_ocp_firmware_header *)fw->data;
	if (memcmp(hdr->magic, OCP_FIRMWARE_MAGIC_HEADER, 4)) {
		devlink_flash_update_status_notify(devlink,
			"No firmware header found, flashing raw image",
			NULL, 0, 0);
		offset = 0;
		length = fw->size;
		goto out;
	}

	if (be16_to_cpu(hdr->pci_vendor_id) != bp->pdev->vendor ||
	    be16_to_cpu(hdr->pci_device_id) != bp->pdev->device) {
		devlink_flash_update_status_notify(devlink,
			"Firmware image compatibility check failed",
			NULL, 0, 0);
		return -EINVAL;
	}

	offset = sizeof(*hdr);
	length = be32_to_cpu(hdr->image_size);
	if (length != (fw->size - offset)) {
		devlink_flash_update_status_notify(devlink,
			"Firmware image size check failed",
			NULL, 0, 0);
		return -EINVAL;
	}

	crc = crc16(0xffff, &fw->data[offset], length);
	if (be16_to_cpu(hdr->crc) != crc) {
		devlink_flash_update_status_notify(devlink,
			"Firmware image CRC check failed",
			NULL, 0, 0);
		return -EINVAL;
	}

out:
	*data = &fw->data[offset];
	*size = length;

	return 0;
}

static int
ptp_ocp_devlink_flash(struct devlink *devlink, struct device *dev,
		      const struct firmware *fw)
{
	struct mtd_info *mtd = dev_get_drvdata(dev);
	struct ptp_ocp *bp = devlink_priv(devlink);
	size_t off, len, resid, wrote;
	size_t off, len, size, resid, wrote;
	struct erase_info erase;
	size_t base, blksz;
	int err = 0;
	const u8 *data;
	int err;

	err = ptp_ocp_devlink_fw_image(devlink, fw, &data, &size);
	if (err)
		goto out;

	off = 0;
	base = bp->flash_start;
	blksz = 4096;
	resid = fw->size;
	resid = size;

	while (resid) {
		devlink_flash_update_status_notify(devlink, "Flashing",
						   NULL, off, fw->size);
						   NULL, off, size);

		len = min_t(size_t, resid, blksz);
		erase.addr = base + off;
@@ -1316,7 +1419,7 @@ ptp_ocp_devlink_flash(struct devlink *devlink, struct device *dev,
		if (err)
			goto out;

		err = mtd_write(mtd, base + off, len, &wrote, &fw->data[off]);
		err = mtd_write(mtd, base + off, len, &wrote, data + off);
		if (err)
			goto out;

@@ -1360,6 +1463,7 @@ ptp_ocp_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
			 struct netlink_ext_ack *extack)
{
	struct ptp_ocp *bp = devlink_priv(devlink);
	const char *fw_image;
	char buf[32];
	int err;

@@ -1367,13 +1471,9 @@ ptp_ocp_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
	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);
	}
	fw_image = bp->fw_loader ? "loader" : "fw";
	sprintf(buf, "%d.%d", bp->fw_tag, bp->fw_version);
	err = devlink_info_version_running_put(req, fw_image, buf);
	if (err)
		return err;

@@ -1403,7 +1503,7 @@ static const struct devlink_ops ptp_ocp_devlink_ops = {
};

static void __iomem *
__ptp_ocp_get_mem(struct ptp_ocp *bp, unsigned long start, int size)
__ptp_ocp_get_mem(struct ptp_ocp *bp, resource_size_t start, int size)
{
	struct resource res = DEFINE_RES_MEM_NAMED(start, size, "ptp_ocp");

@@ -1413,7 +1513,7 @@ __ptp_ocp_get_mem(struct ptp_ocp *bp, unsigned long start, int size)
static void __iomem *
ptp_ocp_get_mem(struct ptp_ocp *bp, struct ocp_resource *r)
{
	unsigned long start;
	resource_size_t start;

	start = pci_resource_start(bp->pdev, 0) + r->offset;
	return __ptp_ocp_get_mem(bp, start, r->size);
@@ -1427,7 +1527,7 @@ ptp_ocp_set_irq_resource(struct resource *res, int irq)
}

static void
ptp_ocp_set_mem_resource(struct resource *res, unsigned long start, int size)
ptp_ocp_set_mem_resource(struct resource *res, resource_size_t start, int size)
{
	struct resource r = DEFINE_RES_MEM(start, size);
	*res = r;
@@ -1440,7 +1540,7 @@ ptp_ocp_register_spi(struct ptp_ocp *bp, struct ocp_resource *r)
	struct pci_dev *pdev = bp->pdev;
	struct platform_device *p;
	struct resource res[2];
	unsigned long start;
	resource_size_t start;
	int id;

	start = pci_resource_start(pdev, 0) + r->offset;
@@ -1467,7 +1567,7 @@ ptp_ocp_i2c_bus(struct pci_dev *pdev, struct ocp_resource *r, int id)
{
	struct ptp_ocp_i2c_info *info;
	struct resource res[2];
	unsigned long start;
	resource_size_t start;

	info = r->extra;
	start = pci_resource_start(pdev, 0) + r->offset;
@@ -1873,7 +1973,134 @@ ptp_ocp_attr_group_add(struct ptp_ocp *bp,
}

static void
ptp_ocp_sma_init(struct ptp_ocp *bp)
ptp_ocp_enable_fpga(u32 __iomem *reg, u32 bit, bool enable)
{
	u32 ctrl;
	bool on;

	ctrl = ioread32(reg);
	on = ctrl & bit;
	if (on ^ enable) {
		ctrl &= ~bit;
		ctrl |= enable ? bit : 0;
		iowrite32(ctrl, reg);
	}
}

static void
ptp_ocp_irig_out(struct ptp_ocp *bp, bool enable)
{
	return ptp_ocp_enable_fpga(&bp->irig_out->ctrl,
				   IRIG_M_CTRL_ENABLE, enable);
}

static void
ptp_ocp_irig_in(struct ptp_ocp *bp, bool enable)
{
	return ptp_ocp_enable_fpga(&bp->irig_in->ctrl,
				   IRIG_S_CTRL_ENABLE, enable);
}

static void
ptp_ocp_dcf_out(struct ptp_ocp *bp, bool enable)
{
	return ptp_ocp_enable_fpga(&bp->dcf_out->ctrl,
				   DCF_M_CTRL_ENABLE, enable);
}

static void
ptp_ocp_dcf_in(struct ptp_ocp *bp, bool enable)
{
	return ptp_ocp_enable_fpga(&bp->dcf_in->ctrl,
				   DCF_S_CTRL_ENABLE, enable);
}

static void
__handle_signal_outputs(struct ptp_ocp *bp, u32 val)
{
	ptp_ocp_irig_out(bp, val & 0x00100010);
	ptp_ocp_dcf_out(bp, val & 0x00200020);
}

static void
__handle_signal_inputs(struct ptp_ocp *bp, u32 val)
{
	ptp_ocp_irig_in(bp, val & 0x00100010);
	ptp_ocp_dcf_in(bp, val & 0x00200020);
}

static u32
ptp_ocp_sma_fb_get(struct ptp_ocp *bp, int sma_nr)
{
	u32 __iomem *gpio;
	u32 shift;

	if (bp->sma[sma_nr - 1].fixed_fcn)
		return (sma_nr - 1) & 1;

	if (bp->sma[sma_nr - 1].mode == SMA_MODE_IN)
		gpio = sma_nr > 2 ? &bp->sma_map2->gpio1 : &bp->sma_map1->gpio1;
	else
		gpio = sma_nr > 2 ? &bp->sma_map1->gpio2 : &bp->sma_map2->gpio2;
	shift = sma_nr & 1 ? 0 : 16;

	return (ioread32(gpio) >> shift) & 0xffff;
}

static int
ptp_ocp_sma_fb_set_output(struct ptp_ocp *bp, int sma_nr, u32 val)
{
	u32 reg, mask, shift;
	unsigned long flags;
	u32 __iomem *gpio;

	gpio = sma_nr > 2 ? &bp->sma_map1->gpio2 : &bp->sma_map2->gpio2;
	shift = sma_nr & 1 ? 0 : 16;

	mask = 0xffff << (16 - shift);

	spin_lock_irqsave(&bp->lock, flags);

	reg = ioread32(gpio);
	reg = (reg & mask) | (val << shift);

	__handle_signal_outputs(bp, reg);

	iowrite32(reg, gpio);

	spin_unlock_irqrestore(&bp->lock, flags);

	return 0;
}

static int
ptp_ocp_sma_fb_set_inputs(struct ptp_ocp *bp, int sma_nr, u32 val)
{
	u32 reg, mask, shift;
	unsigned long flags;
	u32 __iomem *gpio;

	gpio = sma_nr > 2 ? &bp->sma_map2->gpio1 : &bp->sma_map1->gpio1;
	shift = sma_nr & 1 ? 0 : 16;

	mask = 0xffff << (16 - shift);

	spin_lock_irqsave(&bp->lock, flags);

	reg = ioread32(gpio);
	reg = (reg & mask) | (val << shift);

	__handle_signal_inputs(bp, reg);

	iowrite32(reg, gpio);

	spin_unlock_irqrestore(&bp->lock, flags);

	return 0;
}

static void
ptp_ocp_sma_fb_init(struct ptp_ocp *bp)
{
	u32 reg;
	int i;
@@ -1883,6 +2110,8 @@ ptp_ocp_sma_init(struct ptp_ocp *bp)
	bp->sma[1].mode = SMA_MODE_IN;
	bp->sma[2].mode = SMA_MODE_OUT;
	bp->sma[3].mode = SMA_MODE_OUT;
	for (i = 0; i < 4; i++)
		bp->sma[i].default_fcn = i & 1;

	/* If no SMA1 map, the pin functions and directions are fixed. */
	if (!bp->sma_map1) {
@@ -1911,6 +2140,14 @@ ptp_ocp_sma_init(struct ptp_ocp *bp)
	}
}

static const struct ocp_sma_op ocp_fb_sma_op = {
	.tbl		= { ptp_ocp_sma_in, ptp_ocp_sma_out },
	.init		= ptp_ocp_sma_fb_init,
	.get		= ptp_ocp_sma_fb_get,
	.set_inputs	= ptp_ocp_sma_fb_set_inputs,
	.set_output	= ptp_ocp_sma_fb_set_output,
};

static int
ptp_ocp_fb_set_pins(struct ptp_ocp *bp)
{
@@ -1932,22 +2169,50 @@ ptp_ocp_fb_set_pins(struct ptp_ocp *bp)
	return 0;
}

static void
ptp_ocp_fb_set_version(struct ptp_ocp *bp)
{
	u64 cap = OCP_CAP_BASIC;
	u32 version;

	version = ioread32(&bp->image->version);

	/* if lower 16 bits are empty, this is the fw loader. */
	if ((version & 0xffff) == 0) {
		version = version >> 16;
		bp->fw_loader = true;
	}

	bp->fw_tag = version >> 15;
	bp->fw_version = version & 0x7fff;

	if (bp->fw_tag) {
		/* FPGA firmware */
		if (version >= 5)
			cap |= OCP_CAP_SIGNAL | OCP_CAP_FREQ;
	} else {
		/* SOM firmware */
		if (version >= 19)
			cap |= OCP_CAP_SIGNAL;
		if (version >= 20)
			cap |= OCP_CAP_FREQ;
	}

	bp->fw_cap = cap;
}

/* FB specific board initializers; last "resource" registered. */
static int
ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
{
	int ver, err;
	int err;

	bp->flash_start = 1024 * 4096;
	bp->eeprom_map = fb_eeprom_map;
	bp->fw_version = ioread32(&bp->image->version);
	bp->fw_cap = OCP_CAP_BASIC;
	bp->sma_op = &ocp_fb_sma_op;

	ver = bp->fw_version & 0xffff;
	if (ver >= 19)
		bp->fw_cap |= OCP_CAP_SIGNAL;
	if (ver >= 20)
		bp->fw_cap |= OCP_CAP_FREQ;
	ptp_ocp_fb_set_version(bp);

	ptp_ocp_tod_init(bp);
	ptp_ocp_nmea_out_init(bp);
@@ -1997,101 +2262,38 @@ ptp_ocp_register_resources(struct ptp_ocp *bp, kernel_ulong_t driver_data)
	return err;
}

static void
ptp_ocp_enable_fpga(u32 __iomem *reg, u32 bit, bool enable)
{
	u32 ctrl;
	bool on;

	ctrl = ioread32(reg);
	on = ctrl & bit;
	if (on ^ enable) {
		ctrl &= ~bit;
		ctrl |= enable ? bit : 0;
		iowrite32(ctrl, reg);
	}
}

static void
ptp_ocp_irig_out(struct ptp_ocp *bp, bool enable)
{
	return ptp_ocp_enable_fpga(&bp->irig_out->ctrl,
				   IRIG_M_CTRL_ENABLE, enable);
}

static void
ptp_ocp_irig_in(struct ptp_ocp *bp, bool enable)
{
	return ptp_ocp_enable_fpga(&bp->irig_in->ctrl,
				   IRIG_S_CTRL_ENABLE, enable);
}

static void
ptp_ocp_dcf_out(struct ptp_ocp *bp, bool enable)
{
	return ptp_ocp_enable_fpga(&bp->dcf_out->ctrl,
				   DCF_M_CTRL_ENABLE, enable);
}

static void
ptp_ocp_dcf_in(struct ptp_ocp *bp, bool enable)
{
	return ptp_ocp_enable_fpga(&bp->dcf_in->ctrl,
				   DCF_S_CTRL_ENABLE, enable);
}

static void
__handle_signal_outputs(struct ptp_ocp *bp, u32 val)
{
	ptp_ocp_irig_out(bp, val & 0x00100010);
	ptp_ocp_dcf_out(bp, val & 0x00200020);
}

static void
__handle_signal_inputs(struct ptp_ocp *bp, u32 val)
{
	ptp_ocp_irig_in(bp, val & 0x00100010);
	ptp_ocp_dcf_in(bp, val & 0x00200020);
}

/*
 * ANT0 == gps	(in)
 * ANT1 == sma1 (in)
 * ANT2 == sma2 (in)
 * ANT3 == sma3 (out)
 * ANT4 == sma4 (out)
 */

static ssize_t
ptp_ocp_show_output(u32 val, char *buf, int def_val)
ptp_ocp_show_output(const struct ocp_selector *tbl, u32 val, char *buf,
		    int def_val)
{
	const char *name;
	ssize_t count;

	count = sysfs_emit(buf, "OUT: ");
	name = ptp_ocp_select_name_from_val(ptp_ocp_sma_out, val);
	name = ptp_ocp_select_name_from_val(tbl, val);
	if (!name)
		name = ptp_ocp_select_name_from_val(ptp_ocp_sma_out, def_val);
		name = ptp_ocp_select_name_from_val(tbl, def_val);
	count += sysfs_emit_at(buf, count, "%s\n", name);
	return count;
}

static ssize_t
ptp_ocp_show_inputs(u32 val, char *buf, int def_val)
ptp_ocp_show_inputs(const struct ocp_selector *tbl, u32 val, char *buf,
		    int def_val)
{
	const char *name;
	ssize_t count;
	int i;

	count = sysfs_emit(buf, "IN: ");
	for (i = 0; i < ARRAY_SIZE(ptp_ocp_sma_in); i++) {
		if (val & ptp_ocp_sma_in[i].value) {
			name = ptp_ocp_sma_in[i].name;
	for (i = 0; tbl[i].name; i++) {
		if (val & tbl[i].value) {
			name = tbl[i].name;
			count += sysfs_emit_at(buf, count, "%s ", name);
		}
	}
	if (!val && def_val >= 0) {
		name = ptp_ocp_select_name_from_val(ptp_ocp_sma_in, def_val);
		name = ptp_ocp_select_name_from_val(tbl, def_val);
		count += sysfs_emit_at(buf, count, "%s ", name);
	}
	if (count)
@@ -2101,9 +2303,9 @@ ptp_ocp_show_inputs(u32 val, char *buf, int def_val)
}

static int
sma_parse_inputs(const char *buf, enum ptp_ocp_sma_mode *mode)
sma_parse_inputs(const struct ocp_selector * const tbl[], const char *buf,
		 enum ptp_ocp_sma_mode *mode)
{
	struct ocp_selector *tbl[] = { ptp_ocp_sma_in, ptp_ocp_sma_out };
	int idx, count, dir;
	char **argv;
	int ret;
@@ -2139,40 +2341,24 @@ sma_parse_inputs(const char *buf, enum ptp_ocp_sma_mode *mode)
	return ret;
}

static u32
ptp_ocp_sma_get(struct ptp_ocp *bp, int sma_nr, enum ptp_ocp_sma_mode mode)
{
	u32 __iomem *gpio;
	u32 shift;

	if (bp->sma[sma_nr - 1].fixed_fcn)
		return (sma_nr - 1) & 1;

	if (mode == SMA_MODE_IN)
		gpio = sma_nr > 2 ? &bp->sma_map2->gpio1 : &bp->sma_map1->gpio1;
	else
		gpio = sma_nr > 2 ? &bp->sma_map1->gpio2 : &bp->sma_map2->gpio2;
	shift = sma_nr & 1 ? 0 : 16;

	return (ioread32(gpio) >> shift) & 0xffff;
}

static ssize_t
ptp_ocp_sma_show(struct ptp_ocp *bp, int sma_nr, char *buf,
		 int default_in_val, int default_out_val)
{
	struct ptp_ocp_sma_connector *sma = &bp->sma[sma_nr - 1];
	const struct ocp_selector * const *tbl;
	u32 val;

	val = ptp_ocp_sma_get(bp, sma_nr, sma->mode) & SMA_SELECT_MASK;
	tbl = bp->sma_op->tbl;
	val = ptp_ocp_sma_get(bp, sma_nr) & SMA_SELECT_MASK;

	if (sma->mode == SMA_MODE_IN) {
		if (sma->disabled)
			val = SMA_DISABLE;
		return ptp_ocp_show_inputs(val, buf, default_in_val);
		return ptp_ocp_show_inputs(tbl[0], val, buf, default_in_val);
	}

	return ptp_ocp_show_output(val, buf, default_out_val);
	return ptp_ocp_show_output(tbl[1], val, buf, default_out_val);
}

static ssize_t
@@ -2207,54 +2393,6 @@ sma4_show(struct device *dev, struct device_attribute *attr, char *buf)
	return ptp_ocp_sma_show(bp, 4, buf, -1, 1);
}

static void
ptp_ocp_sma_store_output(struct ptp_ocp *bp, int sma_nr, u32 val)
{
	u32 reg, mask, shift;
	unsigned long flags;
	u32 __iomem *gpio;

	gpio = sma_nr > 2 ? &bp->sma_map1->gpio2 : &bp->sma_map2->gpio2;
	shift = sma_nr & 1 ? 0 : 16;

	mask = 0xffff << (16 - shift);

	spin_lock_irqsave(&bp->lock, flags);

	reg = ioread32(gpio);
	reg = (reg & mask) | (val << shift);

	__handle_signal_outputs(bp, reg);

	iowrite32(reg, gpio);

	spin_unlock_irqrestore(&bp->lock, flags);
}

static void
ptp_ocp_sma_store_inputs(struct ptp_ocp *bp, int sma_nr, u32 val)
{
	u32 reg, mask, shift;
	unsigned long flags;
	u32 __iomem *gpio;

	gpio = sma_nr > 2 ? &bp->sma_map2->gpio1 : &bp->sma_map1->gpio1;
	shift = sma_nr & 1 ? 0 : 16;

	mask = 0xffff << (16 - shift);

	spin_lock_irqsave(&bp->lock, flags);

	reg = ioread32(gpio);
	reg = (reg & mask) | (val << shift);

	__handle_signal_inputs(bp, reg);

	iowrite32(reg, gpio);

	spin_unlock_irqrestore(&bp->lock, flags);
}

static int
ptp_ocp_sma_store(struct ptp_ocp *bp, const char *buf, int sma_nr)
{
@@ -2263,7 +2401,7 @@ ptp_ocp_sma_store(struct ptp_ocp *bp, const char *buf, int sma_nr)
	int val;

	mode = sma->mode;
	val = sma_parse_inputs(buf, &mode);
	val = sma_parse_inputs(bp->sma_op->tbl, buf, &mode);
	if (val < 0)
		return val;

@@ -2271,7 +2409,7 @@ ptp_ocp_sma_store(struct ptp_ocp *bp, const char *buf, int sma_nr)
		return -EOPNOTSUPP;

	if (sma->fixed_fcn) {
		if (val != ((sma_nr - 1) & 1))
		if (val != sma->default_fcn)
			return -EOPNOTSUPP;
		return 0;
	}
@@ -2280,9 +2418,9 @@ ptp_ocp_sma_store(struct ptp_ocp *bp, const char *buf, int sma_nr)

	if (mode != sma->mode) {
		if (mode == SMA_MODE_IN)
			ptp_ocp_sma_store_output(bp, sma_nr, 0);
			ptp_ocp_sma_set_output(bp, sma_nr, 0);
		else
			ptp_ocp_sma_store_inputs(bp, sma_nr, 0);
			ptp_ocp_sma_set_inputs(bp, sma_nr, 0);
		sma->mode = mode;
	}

@@ -2293,11 +2431,11 @@ ptp_ocp_sma_store(struct ptp_ocp *bp, const char *buf, int sma_nr)
		val = 0;

	if (mode == SMA_MODE_IN)
		ptp_ocp_sma_store_inputs(bp, sma_nr, val);
		val = ptp_ocp_sma_set_inputs(bp, sma_nr, val);
	else
		ptp_ocp_sma_store_output(bp, sma_nr, val);
		val = ptp_ocp_sma_set_output(bp, sma_nr, val);

	return 0;
	return val;
}

static ssize_t
@@ -2352,7 +2490,9 @@ static ssize_t
available_sma_inputs_show(struct device *dev,
			  struct device_attribute *attr, char *buf)
{
	return ptp_ocp_select_table_show(ptp_ocp_sma_in, buf);
	struct ptp_ocp *bp = dev_get_drvdata(dev);

	return ptp_ocp_select_table_show(bp->sma_op->tbl[0], buf);
}
static DEVICE_ATTR_RO(available_sma_inputs);

@@ -2360,7 +2500,9 @@ static ssize_t
available_sma_outputs_show(struct device *dev,
			   struct device_attribute *attr, char *buf)
{
	return ptp_ocp_select_table_show(ptp_ocp_sma_out, buf);
	struct ptp_ocp *bp = dev_get_drvdata(dev);

	return ptp_ocp_select_table_show(bp->sma_op->tbl[1], buf);
}
static DEVICE_ATTR_RO(available_sma_outputs);

@@ -3025,10 +3167,10 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
	struct device *dev = s->private;
	struct ptp_system_timestamp sts;
	struct ts_reg __iomem *ts_reg;
	char *buf, *src, *mac_src;
	struct timespec64 ts;
	struct ptp_ocp *bp;
	u16 sma_val[4][2];
	char *src, *buf;
	u32 ctrl, val;
	bool on, map;
	int i;
@@ -3191,17 +3333,26 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
	if (bp->pps_select) {
		val = ioread32(&bp->pps_select->gpio1);
		src = &buf[80];
		if (val & 0x01)
		mac_src = "GNSS1";
		if (val & 0x01) {
			gpio_input_map(src, bp, sma_val, 0, NULL);
		else if (val & 0x02)
			mac_src = src;
		} else if (val & 0x02) {
			src = "MAC";
		else if (val & 0x04)
		} else if (val & 0x04) {
			src = "GNSS1";
		else
		} else {
			src = "----";
			mac_src = src;
		}
	} else {
		src = "?";
		mac_src = src;
	}
	seq_printf(s, "MAC PPS1 src: %s\n", mac_src);

	gpio_input_map(buf, bp, sma_val, 1, "GNSS2");
	seq_printf(s, "MAC PPS2 src: %s\n", buf);

	/* assumes automatic switchover/selection */
	val = ioread32(&bp->reg->select);
@@ -3226,12 +3377,6 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
	seq_printf(s, "%7s: %s, state: %s\n", "PHC src", buf,
		   val & OCP_STATUS_IN_SYNC ? "sync" : "unsynced");

	/* reuses PPS1 src from earlier */
	seq_printf(s, "MAC PPS1 src: %s\n", src);

	gpio_input_map(buf, bp, sma_val, 1, "GNSS2");
	seq_printf(s, "MAC PPS2 src: %s\n", buf);

	if (!ptp_ocp_gettimex(&bp->ptp_info, &ts, &sts)) {
		struct timespec64 sys_ts;
		s64 pre_ns, post_ns, ns;
@@ -3498,14 +3643,6 @@ ptp_ocp_info(struct ptp_ocp *bp)

	ptp_ocp_phc_info(bp);

	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);

	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);