diff options
author | Jakub Kicinski <kuba@kernel.org> | 2022-05-24 11:40:00 -0700 |
---|---|---|
committer | Jakub Kicinski <kuba@kernel.org> | 2022-05-24 11:40:01 -0700 |
commit | 57d7becda9c9e612e6b00676f2eecfac3e719e88 (patch) | |
tree | b7eb4e1f59b56679a30eff27cabdc89f3eaea4c0 | |
parent | 9029ac03f20a5999bc5627277c6cf008ab8e23ed (diff) | |
parent | 3c3673bde50c31d1f5ab0b39e9eeb555285786bb (diff) |
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: Jakub Kicinski <kuba@kernel.org>
-rw-r--r-- | drivers/ptp/ptp_ocp.c | 559 |
1 files changed, 348 insertions, 211 deletions
diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c index 860672d6a03c..4519ef42b458 100644 --- a/drivers/ptp/ptp_ocp.c +++ b/drivers/ptp/ptp_ocp.c @@ -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 +#define PCI_VENDOR_ID_FACEBOOK 0x1d9b +#define PCI_DEVICE_ID_FACEBOOK_TIMECARD 0x0400 -#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; @@ -1289,24 +1336,80 @@ ptp_ocp_find_flash(struct ptp_ocp *bp) } 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 @@ out: 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); |