diff options
Diffstat (limited to 'drivers/ptp/ptp_ocp.c')
| -rw-r--r-- | drivers/ptp/ptp_ocp.c | 172 |
1 files changed, 111 insertions, 61 deletions
diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c index 5feecaadde8e..65fe05cac8c4 100644 --- a/drivers/ptp/ptp_ocp.c +++ b/drivers/ptp/ptp_ocp.c @@ -25,8 +25,7 @@ #include <linux/crc16.h> #include <linux/dpll.h> -#define PCI_VENDOR_ID_FACEBOOK 0x1d9b -#define PCI_DEVICE_ID_FACEBOOK_TIMECARD 0x0400 +#define PCI_DEVICE_ID_META_TIMECARD 0x0400 #define PCI_VENDOR_ID_CELESTICA 0x18d4 #define PCI_DEVICE_ID_CELESTICA_TIMECARD 0x1008 @@ -315,6 +314,8 @@ struct ptp_ocp_serial_port { #define OCP_BOARD_ID_LEN 13 #define OCP_SERIAL_LEN 6 #define OCP_SMA_NUM 4 +#define OCP_SIGNAL_NUM 4 +#define OCP_FREQ_NUM 4 enum { PORT_GNSS, @@ -342,8 +343,8 @@ struct ptp_ocp { struct dcf_master_reg __iomem *dcf_out; struct dcf_slave_reg __iomem *dcf_in; struct tod_reg __iomem *nmea_out; - struct frequency_reg __iomem *freq_in[4]; - struct ptp_ocp_ext_src *signal_out[4]; + struct frequency_reg __iomem *freq_in[OCP_FREQ_NUM]; + struct ptp_ocp_ext_src *signal_out[OCP_SIGNAL_NUM]; struct ptp_ocp_ext_src *pps; struct ptp_ocp_ext_src *ts0; struct ptp_ocp_ext_src *ts1; @@ -378,10 +379,12 @@ struct ptp_ocp { u32 utc_tai_offset; u32 ts_window_adjust; u64 fw_cap; - struct ptp_ocp_signal signal[4]; + struct ptp_ocp_signal signal[OCP_SIGNAL_NUM]; struct ptp_ocp_sma_connector sma[OCP_SMA_NUM]; const struct ocp_sma_op *sma_op; struct dpll_device *dpll; + int signals_nr; + int freq_in_nr; }; #define OCP_REQ_TIMESTAMP BIT(0) @@ -1026,7 +1029,7 @@ static struct ocp_resource ocp_adva_resource[] = { }; static const struct pci_device_id ptp_ocp_pcidev_id[] = { - { PCI_DEVICE_DATA(FACEBOOK, TIMECARD, &ocp_fb_resource) }, + { PCI_DEVICE_DATA(META, TIMECARD, &ocp_fb_resource) }, { PCI_DEVICE_DATA(CELESTICA, TIMECARD, &ocp_fb_resource) }, { PCI_DEVICE_DATA(OROLIA, ARTCARD, &ocp_art_resource) }, { PCI_DEVICE_DATA(ADVA, TIMECARD, &ocp_adva_resource) }, @@ -1481,6 +1484,8 @@ static const struct ptp_clock_info ptp_ocp_clock_info = { .pps = true, .n_ext_ts = 6, .n_per_out = 5, + .supported_extts_flags = PTP_STRICT_FLAGS | PTP_RISING_EDGE, + .supported_perout_flags = PTP_PEROUT_DUTY_CYCLE | PTP_PEROUT_PHASE, }; static void @@ -1522,7 +1527,7 @@ ptp_ocp_utc_distribute(struct ptp_ocp *bp, u32 val) static void ptp_ocp_watchdog(struct timer_list *t) { - struct ptp_ocp *bp = from_timer(bp, t, watchdog); + struct ptp_ocp *bp = timer_container_of(bp, t, watchdog); unsigned long flags; u32 status, utc_offset; @@ -2067,6 +2072,7 @@ ptp_ocp_signal_set(struct ptp_ocp *bp, int gen, struct ptp_ocp_signal *s) if (!s->start) { /* roundup() does not work on 32-bit systems */ s->start = DIV64_U64_ROUND_UP(start_ns, s->period); + s->start *= s->period; s->start = ktime_add(s->start, s->phase); } @@ -2218,6 +2224,9 @@ ptp_ocp_ts_enable(void *priv, u32 req, bool enable) static void ptp_ocp_unregister_ext(struct ptp_ocp_ext_src *ext) { + if (!ext) + return; + ext->info->enable(ext, ~0, false); pci_free_irq(ext->bp->pdev, ext->irq_vec, ext); kfree(ext); @@ -2367,7 +2376,7 @@ ptp_ocp_attr_group_add(struct ptp_ocp *bp, if (attr_tbl[i].cap & bp->fw_cap) count++; - bp->attr_group = kcalloc(count + 1, sizeof(struct attribute_group *), + bp->attr_group = kcalloc(count + 1, sizeof(*bp->attr_group), GFP_KERNEL); if (!bp->attr_group) return -ENOMEM; @@ -2541,7 +2550,7 @@ ptp_ocp_sma_fb_init(struct ptp_ocp *bp) for (i = 0; i < OCP_SMA_NUM; i++) { bp->sma[i].fixed_fcn = true; bp->sma[i].fixed_dir = true; - bp->sma[1].dpll_prop.capabilities &= + bp->sma[i].dpll_prop.capabilities &= ~DPLL_PIN_CAPABILITIES_DIRECTION_CAN_CHANGE; } return; @@ -2573,12 +2582,60 @@ static const struct ocp_sma_op ocp_fb_sma_op = { .set_output = ptp_ocp_sma_fb_set_output, }; +static int +ptp_ocp_sma_adva_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); + + iowrite32(reg, gpio); + + spin_unlock_irqrestore(&bp->lock, flags); + + return 0; +} + +static int +ptp_ocp_sma_adva_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); + + iowrite32(reg, gpio); + + spin_unlock_irqrestore(&bp->lock, flags); + + return 0; +} + static const struct ocp_sma_op ocp_adva_sma_op = { .tbl = { ptp_ocp_adva_sma_in, ptp_ocp_adva_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, + .set_inputs = ptp_ocp_sma_adva_set_inputs, + .set_output = ptp_ocp_sma_adva_set_output, }; static int @@ -2644,6 +2701,8 @@ ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r) bp->eeprom_map = fb_eeprom_map; bp->fw_version = ioread32(&bp->image->version); bp->sma_op = &ocp_fb_sma_op; + bp->signals_nr = 4; + bp->freq_in_nr = 4; ptp_ocp_fb_set_version(bp); @@ -2809,6 +2868,8 @@ ptp_ocp_art_board_init(struct ptp_ocp *bp, struct ocp_resource *r) bp->fw_version = ioread32(&bp->reg->version); bp->fw_tag = 2; bp->sma_op = &ocp_art_sma_op; + bp->signals_nr = 4; + bp->freq_in_nr = 4; /* Enable MAC serial port during initialisation */ iowrite32(1, &bp->board_config->mro50_serial_activate); @@ -2835,6 +2896,8 @@ ptp_ocp_adva_board_init(struct ptp_ocp *bp, struct ocp_resource *r) bp->flash_start = 0xA00000; bp->eeprom_map = fb_eeprom_map; bp->sma_op = &ocp_adva_sma_op; + bp->signals_nr = 2; + bp->freq_in_nr = 2; version = ioread32(&bp->image->version); /* if lower 16 bits are empty, this is the fw loader. */ @@ -3189,20 +3252,16 @@ signal_show(struct device *dev, struct device_attribute *attr, char *buf) struct dev_ext_attribute *ea = to_ext_attr(attr); struct ptp_ocp *bp = dev_get_drvdata(dev); struct ptp_ocp_signal *signal; + int gen = (uintptr_t)ea->var; struct timespec64 ts; - ssize_t count; - int i; - - i = (uintptr_t)ea->var; - signal = &bp->signal[i]; - count = sysfs_emit(buf, "%llu %d %llu %d", signal->period, - signal->duty, signal->phase, signal->polarity); + signal = &bp->signal[gen]; ts = ktime_to_timespec64(signal->start); - count += sysfs_emit_at(buf, count, " %ptT TAI\n", &ts); - return count; + return sysfs_emit(buf, "%llu %d %llu %d %ptT TAI\n", + signal->period, signal->duty, signal->phase, signal->polarity, + &ts.tv_sec); } static EXT_ATTR_RW(signal, signal, 0); static EXT_ATTR_RW(signal, signal, 1); @@ -3369,6 +3428,12 @@ ptp_ocp_tty_show(struct device *dev, struct device_attribute *attr, char *buf) struct dev_ext_attribute *ea = to_ext_attr(attr); struct ptp_ocp *bp = dev_get_drvdata(dev); + /* + * NOTE: This output does not include a trailing newline for backward + * compatibility. Existing userspace software uses this value directly + * as a device path (e.g., "/dev/ttyS4"), and adding a newline would + * break those applications. Do not add a newline to this output. + */ return sysfs_emit(buf, "ttyS%d", bp->port[(uintptr_t)ea->var].line); } @@ -3692,7 +3757,7 @@ DEVICE_FREQ_GROUP(freq4, 3); static ssize_t disciplining_config_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct ptp_ocp *bp = dev_get_drvdata(kobj_to_dev(kobj)); @@ -3727,7 +3792,7 @@ out: static ssize_t disciplining_config_write(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct ptp_ocp *bp = dev_get_drvdata(kobj_to_dev(kobj)); @@ -3750,11 +3815,11 @@ disciplining_config_write(struct file *filp, struct kobject *kobj, return err; } -static BIN_ATTR_RW(disciplining_config, OCP_ART_CONFIG_SIZE); +static const BIN_ATTR_RW(disciplining_config, OCP_ART_CONFIG_SIZE); static ssize_t temperature_table_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct ptp_ocp *bp = dev_get_drvdata(kobj_to_dev(kobj)); @@ -3789,7 +3854,7 @@ out: static ssize_t temperature_table_write(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct ptp_ocp *bp = dev_get_drvdata(kobj_to_dev(kobj)); @@ -3812,7 +3877,7 @@ temperature_table_write(struct file *filp, struct kobject *kobj, return err; } -static BIN_ATTR_RW(temperature_table, OCP_ART_TEMP_TABLE_SIZE); +static const BIN_ATTR_RW(temperature_table, OCP_ART_TEMP_TABLE_SIZE); static struct attribute *fb_timecard_attrs[] = { &dev_attr_serialnum.attr, @@ -3867,7 +3932,7 @@ static struct attribute *art_timecard_attrs[] = { NULL, }; -static struct bin_attribute *bin_art_timecard_attrs[] = { +static const struct bin_attribute *const bin_art_timecard_attrs[] = { &bin_attr_disciplining_config, &bin_attr_temperature_table, NULL, @@ -3955,13 +4020,10 @@ _signal_summary_show(struct seq_file *s, struct ptp_ocp *bp, int nr) { struct signal_reg __iomem *reg = bp->signal_out[nr]->mem; struct ptp_ocp_signal *signal = &bp->signal[nr]; - char label[8]; + char label[16]; bool on; u32 val; - if (!signal) - return; - on = signal->running; sprintf(label, "GEN%d", nr + 1); seq_printf(s, "%7s: %s, period:%llu duty:%d%% phase:%llu pol:%d", @@ -3981,7 +4043,7 @@ static void _frequency_summary_show(struct seq_file *s, int nr, struct frequency_reg __iomem *reg) { - char label[8]; + char label[16]; bool on; u32 val; @@ -4125,11 +4187,11 @@ ptp_ocp_summary_show(struct seq_file *s, void *data) } if (bp->fw_cap & OCP_CAP_SIGNAL) - for (i = 0; i < 4; i++) + for (i = 0; i < bp->signals_nr; i++) _signal_summary_show(s, bp, i); if (bp->fw_cap & OCP_CAP_FREQ) - for (i = 0; i < 4; i++) + for (i = 0; i < bp->freq_in_nr; i++) _frequency_summary_show(s, i, bp->freq_in[i]); if (bp->irig_out) { @@ -4229,11 +4291,9 @@ ptp_ocp_summary_show(struct seq_file *s, void *data) ns += (s64)bp->utc_tai_offset * NSEC_PER_SEC; sys_ts = ns_to_timespec64(ns); - seq_printf(s, "%7s: %lld.%ld == %ptT TAI\n", "PHC", - ts.tv_sec, ts.tv_nsec, &ts); - seq_printf(s, "%7s: %lld.%ld == %ptT UTC offset %d\n", "SYS", - sys_ts.tv_sec, sys_ts.tv_nsec, &sys_ts, - bp->utc_tai_offset); + seq_printf(s, "%7s: %ptSp == %ptS TAI\n", "PHC", &ts, &ts); + seq_printf(s, "%7s: %ptSp == %ptS UTC offset %d\n", "SYS", + &sys_ts, &sys_ts, bp->utc_tai_offset); seq_printf(s, "%7s: PHC:SYS offset: %lld window: %lld\n", "", timespec64_to_ns(&ts) - ns, post_ns - pre_ns); @@ -4420,7 +4480,7 @@ ptp_ocp_complete(struct ptp_ocp *bp) pps = pps_lookup_dev(bp->ptp); if (pps) - ptp_ocp_symlink(bp, pps->dev, "pps"); + ptp_ocp_symlink(bp, &pps->dev, "pps"); ptp_ocp_debugfs_add_device(bp); @@ -4441,9 +4501,8 @@ ptp_ocp_phc_info(struct ptp_ocp *bp) ptp_clock_index(bp->ptp)); if (!ptp_ocp_gettimex(&bp->ptp_info, &ts, NULL)) - dev_info(&bp->pdev->dev, "Time: %lld.%ld, %s\n", - ts.tv_sec, ts.tv_nsec, - bp->sync ? "in-sync" : "UNSYNCED"); + dev_info(&bp->pdev->dev, "Time: %ptSp, %s\n", + &ts, bp->sync ? "in-sync" : "UNSYNCED"); } static void @@ -4497,23 +4556,15 @@ ptp_ocp_detach(struct ptp_ocp *bp) ptp_ocp_debugfs_remove_device(bp); ptp_ocp_detach_sysfs(bp); ptp_ocp_attr_group_del(bp); - if (timer_pending(&bp->watchdog)) - del_timer_sync(&bp->watchdog); - if (bp->ts0) - ptp_ocp_unregister_ext(bp->ts0); - if (bp->ts1) - ptp_ocp_unregister_ext(bp->ts1); - if (bp->ts2) - ptp_ocp_unregister_ext(bp->ts2); - if (bp->ts3) - ptp_ocp_unregister_ext(bp->ts3); - if (bp->ts4) - ptp_ocp_unregister_ext(bp->ts4); - if (bp->pps) - ptp_ocp_unregister_ext(bp->pps); + timer_delete_sync(&bp->watchdog); + ptp_ocp_unregister_ext(bp->ts0); + ptp_ocp_unregister_ext(bp->ts1); + ptp_ocp_unregister_ext(bp->ts2); + ptp_ocp_unregister_ext(bp->ts3); + ptp_ocp_unregister_ext(bp->ts4); + ptp_ocp_unregister_ext(bp->pps); for (i = 0; i < 4; i++) - if (bp->signal_out[i]) - ptp_ocp_unregister_ext(bp->signal_out[i]); + ptp_ocp_unregister_ext(bp->signal_out[i]); for (i = 0; i < __PORT_COUNT; i++) if (bp->port[i].line != -1) serial8250_unregister_port(bp->port[i].line); @@ -4766,8 +4817,7 @@ ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id) return 0; out_dpll: - while (i) { - --i; + while (i--) { dpll_pin_unregister(bp->dpll, bp->sma[i].dpll_pin, &dpll_pins_ops, &bp->sma[i]); dpll_pin_put(bp->sma[i].dpll_pin); } |
