summaryrefslogtreecommitdiff
path: root/drivers/ptp
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ptp')
-rw-r--r--drivers/ptp/ptp_clock.c11
-rw-r--r--drivers/ptp/ptp_idt82p33.c344
-rw-r--r--drivers/ptp/ptp_idt82p33.h151
-rw-r--r--drivers/ptp/ptp_ocp.c1688
-rw-r--r--drivers/ptp/ptp_pch.c195
-rw-r--r--drivers/ptp/ptp_sysfs.c4
-rw-r--r--drivers/ptp/ptp_vclock.c56
7 files changed, 1609 insertions, 840 deletions
diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c
index 0e4bc8b9329d..b6f2cfd15dd2 100644
--- a/drivers/ptp/ptp_clock.c
+++ b/drivers/ptp/ptp_clock.c
@@ -317,11 +317,18 @@ no_memory:
}
EXPORT_SYMBOL(ptp_clock_register);
+static int unregister_vclock(struct device *dev, void *data)
+{
+ struct ptp_clock *ptp = dev_get_drvdata(dev);
+
+ ptp_vclock_unregister(info_to_vclock(ptp->info));
+ return 0;
+}
+
int ptp_clock_unregister(struct ptp_clock *ptp)
{
if (ptp_vclock_in_use(ptp)) {
- pr_err("ptp: virtual clock in use\n");
- return -EBUSY;
+ device_for_each_child(&ptp->dev, NULL, unregister_vclock);
}
ptp->defunct = 1;
diff --git a/drivers/ptp/ptp_idt82p33.c b/drivers/ptp/ptp_idt82p33.c
index c1c959f7e52b..97c1be44e323 100644
--- a/drivers/ptp/ptp_idt82p33.c
+++ b/drivers/ptp/ptp_idt82p33.c
@@ -6,13 +6,17 @@
#define pr_fmt(fmt) "IDT_82p33xxx: " fmt
#include <linux/firmware.h>
-#include <linux/i2c.h>
+#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/delay.h>
+#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/timekeeping.h>
#include <linux/bitops.h>
+#include <linux/of.h>
+#include <linux/mfd/rsmu.h>
+#include <linux/mfd/idt82p33_reg.h>
#include "ptp_private.h"
#include "ptp_idt82p33.h"
@@ -24,15 +28,25 @@ MODULE_LICENSE("GPL");
MODULE_FIRMWARE(FW_FILENAME);
/* Module Parameters */
-static u32 sync_tod_timeout = SYNC_TOD_TIMEOUT_SEC;
-module_param(sync_tod_timeout, uint, 0);
-MODULE_PARM_DESC(sync_tod_timeout,
-"duration in second to keep SYNC_TOD on (set to 0 to keep it always on)");
-
static u32 phase_snap_threshold = SNAP_THRESHOLD_NS;
module_param(phase_snap_threshold, uint, 0);
MODULE_PARM_DESC(phase_snap_threshold,
-"threshold (150000ns by default) below which adjtime would ignore");
+"threshold (10000ns by default) below which adjtime would use double dco");
+
+static char *firmware;
+module_param(firmware, charp, 0);
+
+static inline int idt82p33_read(struct idt82p33 *idt82p33, u16 regaddr,
+ u8 *buf, u16 count)
+{
+ return regmap_bulk_read(idt82p33->regmap, regaddr, buf, count);
+}
+
+static inline int idt82p33_write(struct idt82p33 *idt82p33, u16 regaddr,
+ u8 *buf, u16 count)
+{
+ return regmap_bulk_write(idt82p33->regmap, regaddr, buf, count);
+}
static void idt82p33_byte_array_to_timespec(struct timespec64 *ts,
u8 buf[TOD_BYTE_COUNT])
@@ -78,110 +92,6 @@ static void idt82p33_timespec_to_byte_array(struct timespec64 const *ts,
}
}
-static int idt82p33_xfer_read(struct idt82p33 *idt82p33,
- unsigned char regaddr,
- unsigned char *buf,
- unsigned int count)
-{
- struct i2c_client *client = idt82p33->client;
- struct i2c_msg msg[2];
- int cnt;
-
- msg[0].addr = client->addr;
- msg[0].flags = 0;
- msg[0].len = 1;
- msg[0].buf = &regaddr;
-
- msg[1].addr = client->addr;
- msg[1].flags = I2C_M_RD;
- msg[1].len = count;
- msg[1].buf = buf;
-
- cnt = i2c_transfer(client->adapter, msg, 2);
- if (cnt < 0) {
- dev_err(&client->dev, "i2c_transfer returned %d\n", cnt);
- return cnt;
- } else if (cnt != 2) {
- dev_err(&client->dev,
- "i2c_transfer sent only %d of %d messages\n", cnt, 2);
- return -EIO;
- }
- return 0;
-}
-
-static int idt82p33_xfer_write(struct idt82p33 *idt82p33,
- u8 regaddr,
- u8 *buf,
- u16 count)
-{
- struct i2c_client *client = idt82p33->client;
- /* we add 1 byte for device register */
- u8 msg[IDT82P33_MAX_WRITE_COUNT + 1];
- int err;
-
- if (count > IDT82P33_MAX_WRITE_COUNT)
- return -EINVAL;
-
- msg[0] = regaddr;
- memcpy(&msg[1], buf, count);
-
- err = i2c_master_send(client, msg, count + 1);
- if (err < 0) {
- dev_err(&client->dev, "i2c_master_send returned %d\n", err);
- return err;
- }
-
- return 0;
-}
-
-static int idt82p33_page_offset(struct idt82p33 *idt82p33, unsigned char val)
-{
- int err;
-
- if (idt82p33->page_offset == val)
- return 0;
-
- err = idt82p33_xfer_write(idt82p33, PAGE_ADDR, &val, sizeof(val));
- if (err)
- dev_err(&idt82p33->client->dev,
- "failed to set page offset %d\n", val);
- else
- idt82p33->page_offset = val;
-
- return err;
-}
-
-static int idt82p33_rdwr(struct idt82p33 *idt82p33, unsigned int regaddr,
- unsigned char *buf, unsigned int count, bool write)
-{
- u8 offset, page;
- int err;
-
- page = _PAGE(regaddr);
- offset = _OFFSET(regaddr);
-
- err = idt82p33_page_offset(idt82p33, page);
- if (err)
- return err;
-
- if (write)
- return idt82p33_xfer_write(idt82p33, offset, buf, count);
-
- return idt82p33_xfer_read(idt82p33, offset, buf, count);
-}
-
-static int idt82p33_read(struct idt82p33 *idt82p33, unsigned int regaddr,
- unsigned char *buf, unsigned int count)
-{
- return idt82p33_rdwr(idt82p33, regaddr, buf, count, false);
-}
-
-static int idt82p33_write(struct idt82p33 *idt82p33, unsigned int regaddr,
- unsigned char *buf, unsigned int count)
-{
- return idt82p33_rdwr(idt82p33, regaddr, buf, count, true);
-}
-
static int idt82p33_dpll_set_mode(struct idt82p33_channel *channel,
enum pll_mode mode)
{
@@ -206,7 +116,7 @@ static int idt82p33_dpll_set_mode(struct idt82p33_channel *channel,
if (err)
return err;
- channel->pll_mode = dpll_mode;
+ channel->pll_mode = mode;
return 0;
}
@@ -467,7 +377,7 @@ static int idt82p33_measure_tod_write_overhead(struct idt82p33_channel *channel)
err = idt82p33_measure_settime_gettime_gap_overhead(channel, &gap_ns);
if (err) {
- dev_err(&idt82p33->client->dev,
+ dev_err(idt82p33->dev,
"Failed in %s with err %d!\n", __func__, err);
return err;
}
@@ -499,8 +409,8 @@ static int idt82p33_check_and_set_masks(struct idt82p33 *idt82p33,
if (page == PLLMASK_ADDR_HI && offset == PLLMASK_ADDR_LO) {
if ((val & 0xfc) || !(val & 0x3)) {
- dev_err(&idt82p33->client->dev,
- "Invalid PLL mask 0x%hhx\n", val);
+ dev_err(idt82p33->dev,
+ "Invalid PLL mask 0x%x\n", val);
err = -EINVAL;
} else {
idt82p33->pll_mask = val;
@@ -520,14 +430,14 @@ static void idt82p33_display_masks(struct idt82p33 *idt82p33)
{
u8 mask, i;
- dev_info(&idt82p33->client->dev,
+ dev_info(idt82p33->dev,
"pllmask = 0x%02x\n", idt82p33->pll_mask);
for (i = 0; i < MAX_PHC_PLL; i++) {
mask = 1 << i;
if (mask & idt82p33->pll_mask)
- dev_info(&idt82p33->client->dev,
+ dev_info(idt82p33->dev,
"PLL%d output_mask = 0x%04x\n",
i, idt82p33->channel[i].output_mask);
}
@@ -539,11 +449,6 @@ static int idt82p33_sync_tod(struct idt82p33_channel *channel, bool enable)
u8 sync_cnfg;
int err;
- /* Turn it off after sync_tod_timeout seconds */
- if (enable && sync_tod_timeout)
- ptp_schedule_worker(channel->ptp_clock,
- sync_tod_timeout * HZ);
-
err = idt82p33_read(idt82p33, channel->dpll_sync_cnfg,
&sync_cnfg, sizeof(sync_cnfg));
if (err)
@@ -557,22 +462,6 @@ static int idt82p33_sync_tod(struct idt82p33_channel *channel, bool enable)
&sync_cnfg, sizeof(sync_cnfg));
}
-static long idt82p33_sync_tod_work_handler(struct ptp_clock_info *ptp)
-{
- struct idt82p33_channel *channel =
- container_of(ptp, struct idt82p33_channel, caps);
- struct idt82p33 *idt82p33 = channel->idt82p33;
-
- mutex_lock(&idt82p33->reg_lock);
-
- (void)idt82p33_sync_tod(channel, false);
-
- mutex_unlock(&idt82p33->reg_lock);
-
- /* Return a negative value here to not reschedule */
- return -1;
-}
-
static int idt82p33_output_enable(struct idt82p33_channel *channel,
bool enable, unsigned int outn)
{
@@ -634,18 +523,11 @@ static int idt82p33_enable_tod(struct idt82p33_channel *channel)
struct idt82p33 *idt82p33 = channel->idt82p33;
struct timespec64 ts = {0, 0};
int err;
- u8 val;
-
- val = 0;
- err = idt82p33_write(idt82p33, channel->dpll_input_mode_cnfg,
- &val, sizeof(val));
- if (err)
- return err;
err = idt82p33_measure_tod_write_overhead(channel);
if (err) {
- dev_err(&idt82p33->client->dev,
+ dev_err(idt82p33->dev,
"Failed in %s with err %d!\n", __func__, err);
return err;
}
@@ -673,16 +555,14 @@ static void idt82p33_ptp_clock_unregister_all(struct idt82p33 *idt82p33)
}
static int idt82p33_enable(struct ptp_clock_info *ptp,
- struct ptp_clock_request *rq, int on)
+ struct ptp_clock_request *rq, int on)
{
struct idt82p33_channel *channel =
container_of(ptp, struct idt82p33_channel, caps);
struct idt82p33 *idt82p33 = channel->idt82p33;
- int err;
-
- err = -EOPNOTSUPP;
+ int err = -EOPNOTSUPP;
- mutex_lock(&idt82p33->reg_lock);
+ mutex_lock(idt82p33->lock);
if (rq->type == PTP_CLK_REQ_PEROUT) {
if (!on)
@@ -690,15 +570,18 @@ static int idt82p33_enable(struct ptp_clock_info *ptp,
&rq->perout);
/* Only accept a 1-PPS aligned to the second. */
else if (rq->perout.start.nsec || rq->perout.period.sec != 1 ||
- rq->perout.period.nsec) {
+ rq->perout.period.nsec)
err = -ERANGE;
- } else
+ else
err = idt82p33_perout_enable(channel, true,
&rq->perout);
}
- mutex_unlock(&idt82p33->reg_lock);
+ mutex_unlock(idt82p33->lock);
+ if (err)
+ dev_err(idt82p33->dev,
+ "Failed in %s with err %d!\n", __func__, err);
return err;
}
@@ -727,11 +610,11 @@ static int idt82p33_adjwritephase(struct ptp_clock_info *ptp, s32 offset_ns)
val[3] = (offset_regval >> 24) & 0x1F;
val[3] |= PH_OFFSET_EN;
- mutex_lock(&idt82p33->reg_lock);
+ mutex_lock(idt82p33->lock);
err = idt82p33_dpll_set_mode(channel, PLL_MODE_WPH);
if (err) {
- dev_err(&idt82p33->client->dev,
+ dev_err(idt82p33->dev,
"Failed in %s with err %d!\n", __func__, err);
goto out;
}
@@ -740,7 +623,7 @@ static int idt82p33_adjwritephase(struct ptp_clock_info *ptp, s32 offset_ns)
sizeof(val));
out:
- mutex_unlock(&idt82p33->reg_lock);
+ mutex_unlock(idt82p33->lock);
return err;
}
@@ -751,12 +634,12 @@ static int idt82p33_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
struct idt82p33 *idt82p33 = channel->idt82p33;
int err;
- mutex_lock(&idt82p33->reg_lock);
+ mutex_lock(idt82p33->lock);
err = _idt82p33_adjfine(channel, scaled_ppm);
+ mutex_unlock(idt82p33->lock);
if (err)
- dev_err(&idt82p33->client->dev,
+ dev_err(idt82p33->dev,
"Failed in %s with err %d!\n", __func__, err);
- mutex_unlock(&idt82p33->reg_lock);
return err;
}
@@ -768,29 +651,20 @@ static int idt82p33_adjtime(struct ptp_clock_info *ptp, s64 delta_ns)
struct idt82p33 *idt82p33 = channel->idt82p33;
int err;
- mutex_lock(&idt82p33->reg_lock);
+ mutex_lock(idt82p33->lock);
if (abs(delta_ns) < phase_snap_threshold) {
- mutex_unlock(&idt82p33->reg_lock);
+ mutex_unlock(idt82p33->lock);
return 0;
}
err = _idt82p33_adjtime(channel, delta_ns);
- if (err) {
- mutex_unlock(&idt82p33->reg_lock);
- dev_err(&idt82p33->client->dev,
- "Adjtime failed in %s with err %d!\n", __func__, err);
- return err;
- }
+ mutex_unlock(idt82p33->lock);
- err = idt82p33_sync_tod(channel, true);
if (err)
- dev_err(&idt82p33->client->dev,
- "Sync_tod failed in %s with err %d!\n", __func__, err);
-
- mutex_unlock(&idt82p33->reg_lock);
-
+ dev_err(idt82p33->dev,
+ "Failed in %s with err %d!\n", __func__, err);
return err;
}
@@ -801,31 +675,31 @@ static int idt82p33_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
struct idt82p33 *idt82p33 = channel->idt82p33;
int err;
- mutex_lock(&idt82p33->reg_lock);
+ mutex_lock(idt82p33->lock);
err = _idt82p33_gettime(channel, ts);
+ mutex_unlock(idt82p33->lock);
+
if (err)
- dev_err(&idt82p33->client->dev,
+ dev_err(idt82p33->dev,
"Failed in %s with err %d!\n", __func__, err);
- mutex_unlock(&idt82p33->reg_lock);
-
return err;
}
static int idt82p33_settime(struct ptp_clock_info *ptp,
- const struct timespec64 *ts)
+ const struct timespec64 *ts)
{
struct idt82p33_channel *channel =
container_of(ptp, struct idt82p33_channel, caps);
struct idt82p33 *idt82p33 = channel->idt82p33;
int err;
- mutex_lock(&idt82p33->reg_lock);
+ mutex_lock(idt82p33->lock);
err = _idt82p33_settime(channel, ts);
+ mutex_unlock(idt82p33->lock);
+
if (err)
- dev_err(&idt82p33->client->dev,
+ dev_err(idt82p33->dev,
"Failed in %s with err %d!\n", __func__, err);
- mutex_unlock(&idt82p33->reg_lock);
-
return err;
}
@@ -864,7 +738,7 @@ static int idt82p33_channel_init(struct idt82p33_channel *channel, int index)
static void idt82p33_caps_init(struct ptp_clock_info *caps)
{
caps->owner = THIS_MODULE;
- caps->max_adj = 92000;
+ caps->max_adj = DCO_MAX_PPB;
caps->n_per_out = 11;
caps->adjphase = idt82p33_adjwritephase;
caps->adjfine = idt82p33_adjfine;
@@ -872,7 +746,6 @@ static void idt82p33_caps_init(struct ptp_clock_info *caps)
caps->gettime64 = idt82p33_gettime;
caps->settime64 = idt82p33_settime;
caps->enable = idt82p33_enable;
- caps->do_aux_work = idt82p33_sync_tod_work_handler;
}
static int idt82p33_enable_channel(struct idt82p33 *idt82p33, u32 index)
@@ -887,7 +760,7 @@ static int idt82p33_enable_channel(struct idt82p33 *idt82p33, u32 index)
err = idt82p33_channel_init(channel, index);
if (err) {
- dev_err(&idt82p33->client->dev,
+ dev_err(idt82p33->dev,
"Channel_init failed in %s with err %d!\n",
__func__, err);
return err;
@@ -912,7 +785,7 @@ static int idt82p33_enable_channel(struct idt82p33 *idt82p33, u32 index)
err = idt82p33_dpll_set_mode(channel, PLL_MODE_DCO);
if (err) {
- dev_err(&idt82p33->client->dev,
+ dev_err(idt82p33->dev,
"Dpll_set_mode failed in %s with err %d!\n",
__func__, err);
return err;
@@ -920,13 +793,13 @@ static int idt82p33_enable_channel(struct idt82p33 *idt82p33, u32 index)
err = idt82p33_enable_tod(channel);
if (err) {
- dev_err(&idt82p33->client->dev,
+ dev_err(idt82p33->dev,
"Enable_tod failed in %s with err %d!\n",
__func__, err);
return err;
}
- dev_info(&idt82p33->client->dev, "PLL%d registered as ptp%d\n",
+ dev_info(idt82p33->dev, "PLL%d registered as ptp%d\n",
index, channel->ptp_clock->index);
return 0;
@@ -940,25 +813,24 @@ static int idt82p33_load_firmware(struct idt82p33 *idt82p33)
int err;
s32 len;
- dev_dbg(&idt82p33->client->dev,
- "requesting firmware '%s'\n", FW_FILENAME);
+ dev_dbg(idt82p33->dev, "requesting firmware '%s'\n", FW_FILENAME);
- err = request_firmware(&fw, FW_FILENAME, &idt82p33->client->dev);
+ err = request_firmware(&fw, FW_FILENAME, idt82p33->dev);
if (err) {
- dev_err(&idt82p33->client->dev,
+ dev_err(idt82p33->dev,
"Failed in %s with err %d!\n", __func__, err);
return err;
}
- dev_dbg(&idt82p33->client->dev, "firmware size %zu bytes\n", fw->size);
+ dev_dbg(idt82p33->dev, "firmware size %zu bytes\n", fw->size);
rec = (struct idt82p33_fwrc *) fw->data;
for (len = fw->size; len > 0; len -= sizeof(*rec)) {
if (rec->reserved) {
- dev_err(&idt82p33->client->dev,
+ dev_err(idt82p33->dev,
"bad firmware, reserved field non-zero\n");
err = -EINVAL;
} else {
@@ -973,16 +845,11 @@ static int idt82p33_load_firmware(struct idt82p33 *idt82p33)
}
if (err == 0) {
- /* maximum 8 pages */
- if (page >= PAGE_NUM)
- continue;
-
/* Page size 128, last 4 bytes of page skipped */
- if (((loaddr > 0x7b) && (loaddr <= 0x7f))
- || loaddr > 0xfb)
+ if (loaddr > 0x7b)
continue;
- err = idt82p33_write(idt82p33, _ADDR(page, loaddr),
+ err = idt82p33_write(idt82p33, REG_ADDR(page, loaddr),
&val, sizeof(val));
}
@@ -997,36 +864,34 @@ out:
}
-static int idt82p33_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int idt82p33_probe(struct platform_device *pdev)
{
+ struct rsmu_ddata *ddata = dev_get_drvdata(pdev->dev.parent);
struct idt82p33 *idt82p33;
int err;
u8 i;
- (void)id;
-
- idt82p33 = devm_kzalloc(&client->dev,
+ idt82p33 = devm_kzalloc(&pdev->dev,
sizeof(struct idt82p33), GFP_KERNEL);
if (!idt82p33)
return -ENOMEM;
- mutex_init(&idt82p33->reg_lock);
-
- idt82p33->client = client;
- idt82p33->page_offset = 0xff;
+ idt82p33->dev = &pdev->dev;
+ idt82p33->mfd = pdev->dev.parent;
+ idt82p33->lock = &ddata->lock;
+ idt82p33->regmap = ddata->regmap;
idt82p33->tod_write_overhead_ns = 0;
idt82p33->calculate_overhead_flag = 0;
idt82p33->pll_mask = DEFAULT_PLL_MASK;
idt82p33->channel[0].output_mask = DEFAULT_OUTPUT_MASK_PLL0;
idt82p33->channel[1].output_mask = DEFAULT_OUTPUT_MASK_PLL1;
- mutex_lock(&idt82p33->reg_lock);
+ mutex_lock(idt82p33->lock);
err = idt82p33_load_firmware(idt82p33);
if (err)
- dev_warn(&idt82p33->client->dev,
+ dev_warn(idt82p33->dev,
"loading firmware failed with %d\n", err);
if (idt82p33->pll_mask) {
@@ -1034,7 +899,7 @@ static int idt82p33_probe(struct i2c_client *client,
if (idt82p33->pll_mask & (1 << i)) {
err = idt82p33_enable_channel(idt82p33, i);
if (err) {
- dev_err(&idt82p33->client->dev,
+ dev_err(idt82p33->dev,
"Failed in %s with err %d!\n",
__func__, err);
break;
@@ -1042,69 +907,38 @@ static int idt82p33_probe(struct i2c_client *client,
}
}
} else {
- dev_err(&idt82p33->client->dev,
+ dev_err(idt82p33->dev,
"no PLLs flagged as PHCs, nothing to do\n");
err = -ENODEV;
}
- mutex_unlock(&idt82p33->reg_lock);
+ mutex_unlock(idt82p33->lock);
if (err) {
idt82p33_ptp_clock_unregister_all(idt82p33);
return err;
}
- i2c_set_clientdata(client, idt82p33);
+ platform_set_drvdata(pdev, idt82p33);
return 0;
}
-static int idt82p33_remove(struct i2c_client *client)
+static int idt82p33_remove(struct platform_device *pdev)
{
- struct idt82p33 *idt82p33 = i2c_get_clientdata(client);
+ struct idt82p33 *idt82p33 = platform_get_drvdata(pdev);
idt82p33_ptp_clock_unregister_all(idt82p33);
- mutex_destroy(&idt82p33->reg_lock);
return 0;
}
-#ifdef CONFIG_OF
-static const struct of_device_id idt82p33_dt_id[] = {
- { .compatible = "idt,82p33810" },
- { .compatible = "idt,82p33813" },
- { .compatible = "idt,82p33814" },
- { .compatible = "idt,82p33831" },
- { .compatible = "idt,82p33910" },
- { .compatible = "idt,82p33913" },
- { .compatible = "idt,82p33914" },
- { .compatible = "idt,82p33931" },
- {},
-};
-MODULE_DEVICE_TABLE(of, idt82p33_dt_id);
-#endif
-
-static const struct i2c_device_id idt82p33_i2c_id[] = {
- { "idt82p33810", },
- { "idt82p33813", },
- { "idt82p33814", },
- { "idt82p33831", },
- { "idt82p33910", },
- { "idt82p33913", },
- { "idt82p33914", },
- { "idt82p33931", },
- {},
-};
-MODULE_DEVICE_TABLE(i2c, idt82p33_i2c_id);
-
-static struct i2c_driver idt82p33_driver = {
+static struct platform_driver idt82p33_driver = {
.driver = {
- .of_match_table = of_match_ptr(idt82p33_dt_id),
- .name = "idt82p33",
+ .name = "82p33x1x-phc",
},
- .probe = idt82p33_probe,
- .remove = idt82p33_remove,
- .id_table = idt82p33_i2c_id,
+ .probe = idt82p33_probe,
+ .remove = idt82p33_remove,
};
-module_i2c_driver(idt82p33_driver);
+module_platform_driver(idt82p33_driver);
diff --git a/drivers/ptp/ptp_idt82p33.h b/drivers/ptp/ptp_idt82p33.h
index 1c7a0f0872e8..0ea1c35c0f9f 100644
--- a/drivers/ptp/ptp_idt82p33.h
+++ b/drivers/ptp/ptp_idt82p33.h
@@ -8,94 +8,19 @@
#define PTP_IDT82P33_H
#include <linux/ktime.h>
-#include <linux/workqueue.h>
+#include <linux/mfd/idt82p33_reg.h>
+#include <linux/regmap.h>
-
-/* Register Map - AN888_SMUforIEEE_SynchEther_82P33xxx_RevH.pdf */
-#define PAGE_NUM (8)
-#define _ADDR(page, offset) (((page) << 0x7) | ((offset) & 0x7f))
-#define _PAGE(addr) (((addr) >> 0x7) & 0x7)
-#define _OFFSET(addr) ((addr) & 0x7f)
-
-#define DPLL1_TOD_CNFG 0x134
-#define DPLL2_TOD_CNFG 0x1B4
-
-#define DPLL1_TOD_STS 0x10B
-#define DPLL2_TOD_STS 0x18B
-
-#define DPLL1_TOD_TRIGGER 0x115
-#define DPLL2_TOD_TRIGGER 0x195
-
-#define DPLL1_OPERATING_MODE_CNFG 0x120
-#define DPLL2_OPERATING_MODE_CNFG 0x1A0
-
-#define DPLL1_HOLDOVER_FREQ_CNFG 0x12C
-#define DPLL2_HOLDOVER_FREQ_CNFG 0x1AC
-
-#define DPLL1_PHASE_OFFSET_CNFG 0x143
-#define DPLL2_PHASE_OFFSET_CNFG 0x1C3
-
-#define DPLL1_SYNC_EDGE_CNFG 0X140
-#define DPLL2_SYNC_EDGE_CNFG 0X1C0
-
-#define DPLL1_INPUT_MODE_CNFG 0X116
-#define DPLL2_INPUT_MODE_CNFG 0X196
-
-#define OUT_MUX_CNFG(outn) _ADDR(0x6, (0xC * (outn)))
-
-#define PAGE_ADDR 0x7F
-/* Register Map end */
-
-/* Register definitions - AN888_SMUforIEEE_SynchEther_82P33xxx_RevH.pdf*/
-#define TOD_TRIGGER(wr_trig, rd_trig) ((wr_trig & 0xf) << 4 | (rd_trig & 0xf))
-#define SYNC_TOD BIT(1)
-#define PH_OFFSET_EN BIT(7)
-#define SQUELCH_ENABLE BIT(5)
-
-/* Bit definitions for the DPLL_MODE register */
-#define PLL_MODE_SHIFT (0)
-#define PLL_MODE_MASK (0x1F)
-
-#define PEROUT_ENABLE_OUTPUT_MASK (0xdeadbeef)
-
-enum pll_mode {
- PLL_MODE_MIN = 0,
- PLL_MODE_AUTOMATIC = PLL_MODE_MIN,
- PLL_MODE_FORCE_FREERUN = 1,
- PLL_MODE_FORCE_HOLDOVER = 2,
- PLL_MODE_FORCE_LOCKED = 4,
- PLL_MODE_FORCE_PRE_LOCKED2 = 5,
- PLL_MODE_FORCE_PRE_LOCKED = 6,
- PLL_MODE_FORCE_LOST_PHASE = 7,
- PLL_MODE_DCO = 10,
- PLL_MODE_WPH = 18,
- PLL_MODE_MAX = PLL_MODE_WPH,
-};
-
-enum hw_tod_trig_sel {
- HW_TOD_TRIG_SEL_MIN = 0,
- HW_TOD_TRIG_SEL_NO_WRITE = HW_TOD_TRIG_SEL_MIN,
- HW_TOD_TRIG_SEL_SYNC_SEL = 1,
- HW_TOD_TRIG_SEL_IN12 = 2,
- HW_TOD_TRIG_SEL_IN13 = 3,
- HW_TOD_TRIG_SEL_IN14 = 4,
- HW_TOD_TRIG_SEL_TOD_PPS = 5,
- HW_TOD_TRIG_SEL_TIMER_INTERVAL = 6,
- HW_TOD_TRIG_SEL_MSB_PHASE_OFFSET_CNFG = 7,
- HW_TOD_TRIG_SEL_MSB_HOLDOVER_FREQ_CNFG = 8,
- HW_TOD_WR_TRIG_SEL_MSB_TOD_CNFG = 9,
- HW_TOD_RD_TRIG_SEL_LSB_TOD_STS = HW_TOD_WR_TRIG_SEL_MSB_TOD_CNFG,
- WR_TRIG_SEL_MAX = HW_TOD_WR_TRIG_SEL_MSB_TOD_CNFG,
-};
-
-/* Register bit definitions end */
#define FW_FILENAME "idt82p33xxx.bin"
-#define MAX_PHC_PLL (2)
-#define TOD_BYTE_COUNT (10)
-#define MAX_MEASURMENT_COUNT (5)
-#define SNAP_THRESHOLD_NS (150000)
-#define SYNC_TOD_TIMEOUT_SEC (5)
-#define IDT82P33_MAX_WRITE_COUNT (512)
+#define MAX_PHC_PLL (2)
+#define TOD_BYTE_COUNT (10)
+#define DCO_MAX_PPB (92000)
+#define MAX_MEASURMENT_COUNT (5)
+#define SNAP_THRESHOLD_NS (10000)
+#define IMMEDIATE_SNAP_THRESHOLD_NS (50000)
+#define DDCO_THRESHOLD_NS (5)
+#define IDT82P33_MAX_WRITE_COUNT (512)
+#define PEROUT_ENABLE_OUTPUT_MASK (0xdeadbeef)
#define PLLMASK_ADDR_HI 0xFF
#define PLLMASK_ADDR_LO 0xA5
@@ -116,15 +41,25 @@ enum hw_tod_trig_sel {
#define DEFAULT_OUTPUT_MASK_PLL0 (0xc0)
#define DEFAULT_OUTPUT_MASK_PLL1 DEFAULT_OUTPUT_MASK_PLL0
+/**
+ * @brief Maximum absolute value for write phase offset in femtoseconds
+ */
+#define WRITE_PHASE_OFFSET_LIMIT (20000052084ll)
+
+/** @brief Phase offset resolution
+ *
+ * DPLL phase offset = 10^15 fs / ( System Clock * 2^13)
+ * = 10^15 fs / ( 1638400000 * 2^23)
+ * = 74.5058059692382 fs
+ */
+#define IDT_T0DPLL_PHASE_RESOL 74506
+
/* PTP Hardware Clock interface */
struct idt82p33_channel {
struct ptp_clock_info caps;
struct ptp_clock *ptp_clock;
- struct idt82p33 *idt82p33;
- enum pll_mode pll_mode;
- /* task to turn off SYNC_TOD bit after pps sync */
- struct delayed_work sync_tod_work;
- bool sync_tod_on;
+ struct idt82p33 *idt82p33;
+ enum pll_mode pll_mode;
s32 current_freq_ppb;
u8 output_mask;
u16 dpll_tod_cnfg;
@@ -138,15 +73,17 @@ struct idt82p33_channel {
};
struct idt82p33 {
- struct idt82p33_channel channel[MAX_PHC_PLL];
- struct i2c_client *client;
- u8 page_offset;
- u8 pll_mask;
- ktime_t start_time;
- int calculate_overhead_flag;
- s64 tod_write_overhead_ns;
- /* Protects I2C read/modify/write registers from concurrent access */
- struct mutex reg_lock;
+ struct idt82p33_channel channel[MAX_PHC_PLL];
+ struct device *dev;
+ u8 pll_mask;
+ /* Mutex to protect operations from being interrupted */
+ struct mutex *lock;
+ struct regmap *regmap;
+ struct device *mfd;
+ /* Overhead calculation for adjtime */
+ ktime_t start_time;
+ int calculate_overhead_flag;
+ s64 tod_write_overhead_ns;
};
/* firmware interface */
@@ -157,18 +94,4 @@ struct idt82p33_fwrc {
u8 reserved;
} __packed;
-/**
- * @brief Maximum absolute value for write phase offset in femtoseconds
- */
-#define WRITE_PHASE_OFFSET_LIMIT (20000052084ll)
-
-/** @brief Phase offset resolution
- *
- * DPLL phase offset = 10^15 fs / ( System Clock * 2^13)
- * = 10^15 fs / ( 1638400000 * 2^23)
- * = 74.5058059692382 fs
- */
-#define IDT_T0DPLL_PHASE_RESOL 74506
-
-
#endif /* PTP_IDT82P33_H */
diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index 17ad5f0d13b2..c3d0fcf609e3 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -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
@@ -52,6 +54,8 @@ struct ocp_reg {
u32 servo_offset_i;
u32 servo_drift_p;
u32 servo_drift_i;
+ u32 status_offset;
+ u32 status_drift;
};
#define OCP_CTRL_ENABLE BIT(0)
@@ -88,9 +92,10 @@ struct tod_reg {
#define TOD_CTRL_GNSS_MASK ((1U << 4) - 1)
#define TOD_CTRL_GNSS_SHIFT 24
-#define TOD_STATUS_UTC_MASK 0xff
-#define TOD_STATUS_UTC_VALID BIT(8)
-#define TOD_STATUS_LEAP_VALID BIT(16)
+#define TOD_STATUS_UTC_MASK 0xff
+#define TOD_STATUS_UTC_VALID BIT(8)
+#define TOD_STATUS_LEAP_ANNOUNCE BIT(12)
+#define TOD_STATUS_LEAP_VALID BIT(16)
struct ts_reg {
u32 enable;
@@ -174,6 +179,35 @@ struct dcf_slave_reg {
#define DCF_S_CTRL_ENABLE BIT(0)
+struct signal_reg {
+ u32 enable;
+ u32 status;
+ u32 polarity;
+ u32 version;
+ u32 __pad0[4];
+ u32 cable_delay;
+ u32 __pad1[3];
+ u32 intr;
+ u32 intr_mask;
+ u32 __pad2[2];
+ u32 start_ns;
+ u32 start_sec;
+ u32 pulse_ns;
+ u32 pulse_sec;
+ u32 period_ns;
+ u32 period_sec;
+ u32 repeat_count;
+};
+
+struct frequency_reg {
+ u32 ctrl;
+ u32 status;
+};
+#define FREQ_STATUS_VALID BIT(31)
+#define FREQ_STATUS_ERROR BIT(30)
+#define FREQ_STATUS_OVERRUN BIT(29)
+#define FREQ_STATUS_MASK (BIT(24) - 1)
+
struct ptp_ocp_flash_info {
const char *name;
int pci_offset;
@@ -201,6 +235,40 @@ struct ptp_ocp_ext_src {
int irq_vec;
};
+enum ptp_ocp_sma_mode {
+ SMA_MODE_IN,
+ SMA_MODE_OUT,
+};
+
+struct ptp_ocp_sma_connector {
+ enum ptp_ocp_sma_mode mode;
+ bool fixed_fcn;
+ bool fixed_dir;
+ bool disabled;
+};
+
+struct ocp_attr_group {
+ u64 cap;
+ const struct attribute_group *group;
+};
+
+#define OCP_CAP_BASIC BIT(0)
+#define OCP_CAP_SIGNAL BIT(1)
+#define OCP_CAP_FREQ BIT(2)
+
+struct ptp_ocp_signal {
+ ktime_t period;
+ ktime_t pulse;
+ ktime_t phase;
+ ktime_t start;
+ int duty;
+ bool polarity;
+ bool running;
+};
+
+#define OCP_BOARD_ID_LEN 13
+#define OCP_SERIAL_LEN 6
+
struct ptp_ocp {
struct pci_dev *pdev;
struct device dev;
@@ -210,16 +278,21 @@ struct ptp_ocp {
struct pps_reg __iomem *pps_to_ext;
struct pps_reg __iomem *pps_to_clk;
struct gpio_reg __iomem *pps_select;
- struct gpio_reg __iomem *sma;
+ struct gpio_reg __iomem *sma_map1;
+ struct gpio_reg __iomem *sma_map2;
struct irig_master_reg __iomem *irig_out;
struct irig_slave_reg __iomem *irig_in;
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 ptp_ocp_ext_src *pps;
struct ptp_ocp_ext_src *ts0;
struct ptp_ocp_ext_src *ts1;
struct ptp_ocp_ext_src *ts2;
+ struct ptp_ocp_ext_src *ts3;
+ struct ptp_ocp_ext_src *ts4;
struct img_reg __iomem *image;
struct ptp_clock *ptp;
struct ptp_clock_info ptp_info;
@@ -227,6 +300,8 @@ struct ptp_ocp {
struct platform_device *spi_flash;
struct clk_hw *i2c_clk;
struct timer_list watchdog;
+ const struct ocp_attr_group *attr_tbl;
+ const struct ptp_ocp_eeprom_map *eeprom_map;
struct dentry *debug_root;
time64_t gnss_lost;
int id;
@@ -235,12 +310,17 @@ 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;
u32 ts_window_adjust;
+ u64 fw_cap;
+ struct ptp_ocp_signal signal[4];
+ struct ptp_ocp_sma_connector sma[4];
};
#define OCP_REQ_TIMESTAMP BIT(0)
@@ -263,7 +343,36 @@ static int ptp_ocp_register_serial(struct ptp_ocp *bp, struct ocp_resource *r);
static int ptp_ocp_register_ext(struct ptp_ocp *bp, struct ocp_resource *r);
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 irqreturn_t ptp_ocp_signal_irq(int irq, void *priv);
static int ptp_ocp_ts_enable(void *priv, u32 req, bool enable);
+static int ptp_ocp_signal_from_perout(struct ptp_ocp *bp, int gen,
+ struct ptp_perout_request *req);
+static int ptp_ocp_signal_enable(void *priv, u32 req, bool enable);
+static int ptp_ocp_sma_store(struct ptp_ocp *bp, const char *buf, int sma_nr);
+
+static const struct ocp_attr_group fb_timecard_groups[];
+
+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; \
@@ -289,10 +398,10 @@ static int ptp_ocp_ts_enable(void *priv, u32 req, bool enable);
OCP_RES_LOCATION(member), .setup = ptp_ocp_register_ext
/* This is the MSI vector mapping used.
- * 0: TS3 (and PPS)
+ * 0: PPS (TS5)
* 1: TS0
* 2: TS1
- * 3: GNSS
+ * 3: GNSS1
* 4: GNSS2
* 5: MAC
* 6: TS2
@@ -300,6 +409,12 @@ static int ptp_ocp_ts_enable(void *priv, u32 req, bool enable);
* 8: HWICAP (notused)
* 9: SPI Flash
* 10: NMEA
+ * 11: Signal Generator 1
+ * 12: Signal Generator 2
+ * 13: Signal Generator 3
+ * 14: Signal Generator 4
+ * 15: TS3
+ * 16: TS4
*/
static struct ocp_resource ocp_fb_resource[] = {
@@ -335,15 +450,70 @@ static struct ocp_resource ocp_fb_resource[] = {
},
},
{
+ OCP_EXT_RESOURCE(ts3),
+ .offset = 0x01110000, .size = 0x10000, .irq_vec = 15,
+ .extra = &(struct ptp_ocp_ext_info) {
+ .index = 3,
+ .irq_fcn = ptp_ocp_ts_irq,
+ .enable = ptp_ocp_ts_enable,
+ },
+ },
+ {
+ OCP_EXT_RESOURCE(ts4),
+ .offset = 0x01120000, .size = 0x10000, .irq_vec = 16,
+ .extra = &(struct ptp_ocp_ext_info) {
+ .index = 4,
+ .irq_fcn = ptp_ocp_ts_irq,
+ .enable = ptp_ocp_ts_enable,
+ },
+ },
+ /* Timestamp for PHC and/or PPS generator */
+ {
OCP_EXT_RESOURCE(pps),
.offset = 0x010C0000, .size = 0x10000, .irq_vec = 0,
.extra = &(struct ptp_ocp_ext_info) {
- .index = 3,
+ .index = 5,
.irq_fcn = ptp_ocp_ts_irq,
.enable = ptp_ocp_ts_enable,
},
},
{
+ OCP_EXT_RESOURCE(signal_out[0]),
+ .offset = 0x010D0000, .size = 0x10000, .irq_vec = 11,
+ .extra = &(struct ptp_ocp_ext_info) {
+ .index = 1,
+ .irq_fcn = ptp_ocp_signal_irq,
+ .enable = ptp_ocp_signal_enable,
+ },
+ },
+ {
+ OCP_EXT_RESOURCE(signal_out[1]),
+ .offset = 0x010E0000, .size = 0x10000, .irq_vec = 12,
+ .extra = &(struct ptp_ocp_ext_info) {
+ .index = 2,
+ .irq_fcn = ptp_ocp_signal_irq,
+ .enable = ptp_ocp_signal_enable,
+ },
+ },
+ {
+ OCP_EXT_RESOURCE(signal_out[2]),
+ .offset = 0x010F0000, .size = 0x10000, .irq_vec = 13,
+ .extra = &(struct ptp_ocp_ext_info) {
+ .index = 3,
+ .irq_fcn = ptp_ocp_signal_irq,
+ .enable = ptp_ocp_signal_enable,
+ },
+ },
+ {
+ OCP_EXT_RESOURCE(signal_out[3]),
+ .offset = 0x01100000, .size = 0x10000, .irq_vec = 14,
+ .extra = &(struct ptp_ocp_ext_info) {
+ .index = 4,
+ .irq_fcn = ptp_ocp_signal_irq,
+ .enable = ptp_ocp_signal_enable,
+ },
+ },
+ {
OCP_MEM_RESOURCE(pps_to_ext),
.offset = 0x01030000, .size = 0x10000,
},
@@ -384,15 +554,28 @@ static struct ocp_resource ocp_fb_resource[] = {
.offset = 0x00130000, .size = 0x1000,
},
{
- OCP_MEM_RESOURCE(sma),
+ OCP_MEM_RESOURCE(sma_map1),
.offset = 0x00140000, .size = 0x1000,
},
{
+ OCP_MEM_RESOURCE(sma_map2),
+ .offset = 0x00220000, .size = 0x1000,
+ },
+ {
OCP_I2C_RESOURCE(i2c_ctrl),
.offset = 0x00150000, .size = 0x10000, .irq_vec = 7,
.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" },
+ },
+ },
},
},
{
@@ -428,6 +611,22 @@ static struct ocp_resource ocp_fb_resource[] = {
},
},
{
+ OCP_MEM_RESOURCE(freq_in[0]),
+ .offset = 0x01200000, .size = 0x10000,
+ },
+ {
+ OCP_MEM_RESOURCE(freq_in[1]),
+ .offset = 0x01210000, .size = 0x10000,
+ },
+ {
+ OCP_MEM_RESOURCE(freq_in[2]),
+ .offset = 0x01220000, .size = 0x10000,
+ },
+ {
+ OCP_MEM_RESOURCE(freq_in[3]),
+ .offset = 0x01230000, .size = 0x10000,
+ },
+ {
.setup = ptp_ocp_fb_board_init,
},
{ }
@@ -460,25 +659,42 @@ static struct ocp_selector ptp_ocp_clock[] = {
{ }
};
+#define SMA_ENABLE BIT(15)
+#define SMA_SELECT_MASK ((1U << 15) - 1)
+#define SMA_DISABLE 0x10000
+
static struct ocp_selector ptp_ocp_sma_in[] = {
- { .name = "10Mhz", .value = 0x00 },
- { .name = "PPS1", .value = 0x01 },
- { .name = "PPS2", .value = 0x02 },
- { .name = "TS1", .value = 0x04 },
- { .name = "TS2", .value = 0x08 },
- { .name = "IRIG", .value = 0x10 },
- { .name = "DCF", .value = 0x20 },
+ { .name = "10Mhz", .value = 0x0000 },
+ { .name = "PPS1", .value = 0x0001 },
+ { .name = "PPS2", .value = 0x0002 },
+ { .name = "TS1", .value = 0x0004 },
+ { .name = "TS2", .value = 0x0008 },
+ { .name = "IRIG", .value = 0x0010 },
+ { .name = "DCF", .value = 0x0020 },
+ { .name = "TS3", .value = 0x0040 },
+ { .name = "TS4", .value = 0x0080 },
+ { .name = "FREQ1", .value = 0x0100 },
+ { .name = "FREQ2", .value = 0x0200 },
+ { .name = "FREQ3", .value = 0x0400 },
+ { .name = "FREQ4", .value = 0x0800 },
+ { .name = "None", .value = SMA_DISABLE },
{ }
};
static struct ocp_selector ptp_ocp_sma_out[] = {
- { .name = "10Mhz", .value = 0x00 },
- { .name = "PHC", .value = 0x01 },
- { .name = "MAC", .value = 0x02 },
- { .name = "GNSS", .value = 0x04 },
- { .name = "GNSS2", .value = 0x08 },
- { .name = "IRIG", .value = 0x10 },
- { .name = "DCF", .value = 0x20 },
+ { .name = "10Mhz", .value = 0x0000 },
+ { .name = "PHC", .value = 0x0001 },
+ { .name = "MAC", .value = 0x0002 },
+ { .name = "GNSS1", .value = 0x0004 },
+ { .name = "GNSS2", .value = 0x0008 },
+ { .name = "IRIG", .value = 0x0010 },
+ { .name = "DCF", .value = 0x0020 },
+ { .name = "GEN1", .value = 0x0040 },
+ { .name = "GEN2", .value = 0x0080 },
+ { .name = "GEN3", .value = 0x0100 },
+ { .name = "GEN4", .value = 0x0200 },
+ { .name = "GND", .value = 0x2000 },
+ { .name = "VCC", .value = 0x4000 },
{ }
};
@@ -700,6 +916,12 @@ ptp_ocp_enable(struct ptp_clock_info *ptp_info, struct ptp_clock_request *rq,
ext = bp->ts2;
break;
case 3:
+ ext = bp->ts3;
+ break;
+ case 4:
+ ext = bp->ts4;
+ break;
+ case 5:
ext = bp->pps;
break;
}
@@ -709,13 +931,27 @@ ptp_ocp_enable(struct ptp_clock_info *ptp_info, struct ptp_clock_request *rq,
ext = bp->pps;
break;
case PTP_CLK_REQ_PEROUT:
- if (on &&
- (rq->perout.period.sec != 1 || rq->perout.period.nsec != 0))
- return -EINVAL;
- /* This is a request for 1PPS on an output SMA.
- * Allow, but assume manual configuration.
- */
- return 0;
+ switch (rq->perout.index) {
+ case 0:
+ /* This is a request for 1PPS on an output SMA.
+ * Allow, but assume manual configuration.
+ */
+ if (on && (rq->perout.period.sec != 1 ||
+ rq->perout.period.nsec != 0))
+ return -EINVAL;
+ return 0;
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ req = rq->perout.index - 1;
+ ext = bp->signal_out[req];
+ err = ptp_ocp_signal_from_perout(bp, req, &rq->perout);
+ if (err)
+ return err;
+ break;
+ }
+ break;
default:
return -EOPNOTSUPP;
}
@@ -727,6 +963,36 @@ ptp_ocp_enable(struct ptp_clock_info *ptp_info, struct ptp_clock_request *rq,
return err;
}
+static int
+ptp_ocp_verify(struct ptp_clock_info *ptp_info, unsigned pin,
+ enum ptp_pin_function func, unsigned chan)
+{
+ struct ptp_ocp *bp = container_of(ptp_info, struct ptp_ocp, ptp_info);
+ char buf[16];
+
+ switch (func) {
+ case PTP_PF_NONE:
+ snprintf(buf, sizeof(buf), "IN: None");
+ break;
+ case PTP_PF_EXTTS:
+ /* Allow timestamps, but require sysfs configuration. */
+ return 0;
+ case PTP_PF_PEROUT:
+ /* channel 0 is 1PPS from PHC.
+ * channels 1..4 are the frequency generators.
+ */
+ if (chan)
+ snprintf(buf, sizeof(buf), "OUT: GEN%d", chan);
+ else
+ snprintf(buf, sizeof(buf), "OUT: PHC");
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return ptp_ocp_sma_store(bp, buf, pin + 1);
+}
+
static const struct ptp_clock_info ptp_ocp_clock_info = {
.owner = THIS_MODULE,
.name = KBUILD_MODNAME,
@@ -737,9 +1003,10 @@ static const struct ptp_clock_info ptp_ocp_clock_info = {
.adjfine = ptp_ocp_null_adjfine,
.adjphase = ptp_ocp_null_adjphase,
.enable = ptp_ocp_enable,
+ .verify = ptp_ocp_verify,
.pps = true,
- .n_ext_ts = 4,
- .n_per_out = 1,
+ .n_ext_ts = 6,
+ .n_per_out = 5,
};
static void
@@ -760,11 +1027,30 @@ __ptp_ocp_clear_drift_locked(struct ptp_ocp *bp)
}
static void
+ptp_ocp_utc_distribute(struct ptp_ocp *bp, u32 val)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&bp->lock, flags);
+
+ bp->utc_tai_offset = val;
+
+ if (bp->irig_out)
+ iowrite32(val, &bp->irig_out->adj_sec);
+ if (bp->dcf_out)
+ iowrite32(val, &bp->dcf_out->adj_sec);
+ if (bp->nmea_out)
+ iowrite32(val, &bp->nmea_out->adj_sec);
+
+ spin_unlock_irqrestore(&bp->lock, flags);
+}
+
+static void
ptp_ocp_watchdog(struct timer_list *t)
{
struct ptp_ocp *bp = from_timer(bp, t, watchdog);
unsigned long flags;
- u32 status;
+ u32 status, utc_offset;
status = ioread32(&bp->pps_to_clk->status);
@@ -781,6 +1067,17 @@ ptp_ocp_watchdog(struct timer_list *t)
bp->gnss_lost = 0;
}
+ /* if GNSS provides correct data we can rely on
+ * it to get leap second information
+ */
+ if (bp->tod) {
+ status = ioread32(&bp->tod->utc_status);
+ utc_offset = status & TOD_STATUS_UTC_MASK;
+ if (status & TOD_STATUS_UTC_VALID &&
+ utc_offset != bp->utc_tai_offset)
+ ptp_ocp_utc_distribute(bp, utc_offset);
+ }
+
mod_timer(&bp->watchdog, jiffies + HZ);
}
@@ -850,25 +1147,6 @@ ptp_ocp_init_clock(struct ptp_ocp *bp)
}
static void
-ptp_ocp_utc_distribute(struct ptp_ocp *bp, u32 val)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&bp->lock, flags);
-
- bp->utc_tai_offset = val;
-
- if (bp->irig_out)
- iowrite32(val, &bp->irig_out->adj_sec);
- if (bp->dcf_out)
- iowrite32(val, &bp->dcf_out->adj_sec);
- if (bp->nmea_out)
- iowrite32(val, &bp->nmea_out->adj_sec);
-
- spin_unlock_irqrestore(&bp->lock, flags);
-}
-
-static void
ptp_ocp_tod_init(struct ptp_ocp *bp)
{
u32 ctrl, reg;
@@ -883,119 +1161,110 @@ ptp_ocp_tod_init(struct ptp_ocp *bp)
ptp_ocp_utc_distribute(bp, reg & TOD_STATUS_UTC_MASK);
}
-static void
-ptp_ocp_tod_info(struct ptp_ocp *bp)
+static const char *
+ptp_ocp_tod_proto_name(const int idx)
{
static const char * const proto_name[] = {
"NMEA", "NMEA_ZDA", "NMEA_RMC", "NMEA_none",
"UBX", "UBX_UTC", "UBX_LS", "UBX_none"
};
+ return proto_name[idx];
+}
+
+static const char *
+ptp_ocp_tod_gnss_name(int idx)
+{
static const char * const gnss_name[] = {
"ALL", "COMBINED", "GPS", "GLONASS", "GALILEO", "BEIDOU",
+ "Unknown"
};
- u32 version, ctrl, reg;
- int idx;
-
- version = ioread32(&bp->tod->version);
- dev_info(&bp->pdev->dev, "TOD Version %d.%d.%d\n",
- version >> 24, (version >> 16) & 0xff, version & 0xffff);
-
- ctrl = ioread32(&bp->tod->ctrl);
- idx = ctrl & TOD_CTRL_PROTOCOL ? 4 : 0;
- idx += (ctrl >> 16) & 3;
- dev_info(&bp->pdev->dev, "control: %x\n", ctrl);
- dev_info(&bp->pdev->dev, "TOD Protocol %s %s\n", proto_name[idx],
- ctrl & TOD_CTRL_ENABLE ? "enabled" : "");
+ if (idx >= ARRAY_SIZE(gnss_name))
+ idx = ARRAY_SIZE(gnss_name) - 1;
+ return gnss_name[idx];
+}
- idx = (ctrl >> TOD_CTRL_GNSS_SHIFT) & TOD_CTRL_GNSS_MASK;
- if (idx < ARRAY_SIZE(gnss_name))
- dev_info(&bp->pdev->dev, "GNSS %s\n", gnss_name[idx]);
+struct ptp_ocp_nvmem_match_info {
+ struct ptp_ocp *bp;
+ const void * const tag;
+};
- reg = ioread32(&bp->tod->status);
- dev_info(&bp->pdev->dev, "status: %x\n", reg);
+static int
+ptp_ocp_nvmem_match(struct device *dev, const void *data)
+{
+ const struct ptp_ocp_nvmem_match_info *info = data;
- reg = ioread32(&bp->tod->adj_sec);
- dev_info(&bp->pdev->dev, "correction: %d\n", reg);
+ dev = dev->parent;
+ if (!i2c_verify_client(dev) || info->tag != dev->platform_data)
+ return 0;
- reg = ioread32(&bp->tod->utc_status);
- dev_info(&bp->pdev->dev, "utc_status: %x\n", reg);
- dev_info(&bp->pdev->dev, "utc_offset: %d valid:%d leap_valid:%d\n",
- reg & TOD_STATUS_UTC_MASK, reg & TOD_STATUS_UTC_VALID ? 1 : 0,
- reg & TOD_STATUS_LEAP_VALID ? 1 : 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_firstchild(struct device *dev, void *data)
+static inline struct nvmem_device *
+ptp_ocp_nvmem_device_get(struct ptp_ocp *bp, const void * const tag)
{
- return 1;
+ struct ptp_ocp_nvmem_match_info info = { .bp = bp, .tag = tag };
+
+ return nvmem_device_find(&info, ptp_ocp_nvmem_match);
}
-static int
-ptp_ocp_read_i2c(struct i2c_adapter *adap, u8 addr, u8 reg, u8 sz, u8 *data)
+static inline void
+ptp_ocp_nvmem_device_put(struct nvmem_device **nvmemp)
{
- 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;
+ 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;
- }
-
- 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;
- }
+ tag = NULL;
+ nvmem = NULL;
- 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 *
@@ -1096,34 +1365,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;
}
@@ -1240,6 +1508,137 @@ ptp_ocp_register_i2c(struct ptp_ocp *bp, struct ocp_resource *r)
return 0;
}
+/* The expectation is that this is triggered only on error. */
+static irqreturn_t
+ptp_ocp_signal_irq(int irq, void *priv)
+{
+ struct ptp_ocp_ext_src *ext = priv;
+ struct signal_reg __iomem *reg = ext->mem;
+ struct ptp_ocp *bp = ext->bp;
+ u32 enable, status;
+ int gen;
+
+ gen = ext->info->index - 1;
+
+ enable = ioread32(&reg->enable);
+ status = ioread32(&reg->status);
+
+ /* disable generator on error */
+ if (status || !enable) {
+ iowrite32(0, &reg->intr_mask);
+ iowrite32(0, &reg->enable);
+ bp->signal[gen].running = false;
+ }
+
+ iowrite32(0, &reg->intr); /* ack interrupt */
+
+ return IRQ_HANDLED;
+}
+
+static int
+ptp_ocp_signal_set(struct ptp_ocp *bp, int gen, struct ptp_ocp_signal *s)
+{
+ struct ptp_system_timestamp sts;
+ struct timespec64 ts;
+ ktime_t start_ns;
+ int err;
+
+ if (!s->period)
+ return 0;
+
+ if (!s->pulse)
+ s->pulse = ktime_divns(s->period * s->duty, 100);
+
+ err = ptp_ocp_gettimex(&bp->ptp_info, &ts, &sts);
+ if (err)
+ return err;
+
+ start_ns = ktime_set(ts.tv_sec, ts.tv_nsec) + NSEC_PER_MSEC;
+ if (!s->start) {
+ /* roundup() does not work on 32-bit systems */
+ s->start = DIV_ROUND_UP_ULL(start_ns, s->period);
+ s->start = ktime_add(s->start, s->phase);
+ }
+
+ if (s->duty < 1 || s->duty > 99)
+ return -EINVAL;
+
+ if (s->pulse < 1 || s->pulse > s->period)
+ return -EINVAL;
+
+ if (s->start < start_ns)
+ return -EINVAL;
+
+ bp->signal[gen] = *s;
+
+ return 0;
+}
+
+static int
+ptp_ocp_signal_from_perout(struct ptp_ocp *bp, int gen,
+ struct ptp_perout_request *req)
+{
+ struct ptp_ocp_signal s = { };
+
+ s.polarity = bp->signal[gen].polarity;
+ s.period = ktime_set(req->period.sec, req->period.nsec);
+ if (!s.period)
+ return 0;
+
+ if (req->flags & PTP_PEROUT_DUTY_CYCLE) {
+ s.pulse = ktime_set(req->on.sec, req->on.nsec);
+ s.duty = ktime_divns(s.pulse * 100, s.period);
+ }
+
+ if (req->flags & PTP_PEROUT_PHASE)
+ s.phase = ktime_set(req->phase.sec, req->phase.nsec);
+ else
+ s.start = ktime_set(req->start.sec, req->start.nsec);
+
+ return ptp_ocp_signal_set(bp, gen, &s);
+}
+
+static int
+ptp_ocp_signal_enable(void *priv, u32 req, bool enable)
+{
+ struct ptp_ocp_ext_src *ext = priv;
+ struct signal_reg __iomem *reg = ext->mem;
+ struct ptp_ocp *bp = ext->bp;
+ struct timespec64 ts;
+ int gen;
+
+ gen = ext->info->index - 1;
+
+ iowrite32(0, &reg->intr_mask);
+ iowrite32(0, &reg->enable);
+ bp->signal[gen].running = false;
+ if (!enable)
+ return 0;
+
+ ts = ktime_to_timespec64(bp->signal[gen].start);
+ iowrite32(ts.tv_sec, &reg->start_sec);
+ iowrite32(ts.tv_nsec, &reg->start_ns);
+
+ ts = ktime_to_timespec64(bp->signal[gen].period);
+ iowrite32(ts.tv_sec, &reg->period_sec);
+ iowrite32(ts.tv_nsec, &reg->period_ns);
+
+ ts = ktime_to_timespec64(bp->signal[gen].pulse);
+ iowrite32(ts.tv_sec, &reg->pulse_sec);
+ iowrite32(ts.tv_nsec, &reg->pulse_ns);
+
+ iowrite32(bp->signal[gen].polarity, &reg->polarity);
+ iowrite32(0, &reg->repeat_count);
+
+ iowrite32(0, &reg->intr); /* clear interrupt state */
+ iowrite32(1, &reg->intr_mask); /* enable interrupt */
+ iowrite32(3, &reg->enable); /* valid & enable */
+
+ bp->signal[gen].running = true;
+
+ return 0;
+}
+
static irqreturn_t
ptp_ocp_ts_irq(int irq, void *priv)
{
@@ -1367,7 +1766,7 @@ ptp_ocp_serial_line(struct ptp_ocp *bp, struct ocp_resource *r)
uart.port.mapbase = pci_resource_start(pdev, 0) + r->offset;
uart.port.irq = pci_irq_vector(pdev, r->irq_vec);
uart.port.uartclk = 50000000;
- uart.port.flags = UPF_FIXED_TYPE | UPF_IOREMAP;
+ uart.port.flags = UPF_FIXED_TYPE | UPF_IOREMAP | UPF_NO_THRE_TEST;
uart.port.type = PORT_16550A;
return serial8250_register_8250_port(&uart);
@@ -1412,14 +1811,115 @@ ptp_ocp_nmea_out_init(struct ptp_ocp *bp)
iowrite32(1, &bp->nmea_out->ctrl); /* enable */
}
+static void
+_ptp_ocp_signal_init(struct ptp_ocp_signal *s, struct signal_reg __iomem *reg)
+{
+ u32 val;
+
+ iowrite32(0, &reg->enable); /* disable */
+
+ val = ioread32(&reg->polarity);
+ s->polarity = val ? true : false;
+ s->duty = 50;
+}
+
+static void
+ptp_ocp_signal_init(struct ptp_ocp *bp)
+{
+ int i;
+
+ for (i = 0; i < 4; i++)
+ if (bp->signal_out[i])
+ _ptp_ocp_signal_init(&bp->signal[i],
+ bp->signal_out[i]->mem);
+}
+
+static void
+ptp_ocp_sma_init(struct ptp_ocp *bp)
+{
+ u32 reg;
+ int i;
+
+ /* defaults */
+ bp->sma[0].mode = SMA_MODE_IN;
+ bp->sma[1].mode = SMA_MODE_IN;
+ bp->sma[2].mode = SMA_MODE_OUT;
+ bp->sma[3].mode = SMA_MODE_OUT;
+
+ /* If no SMA1 map, the pin functions and directions are fixed. */
+ if (!bp->sma_map1) {
+ for (i = 0; i < 4; i++) {
+ bp->sma[i].fixed_fcn = true;
+ bp->sma[i].fixed_dir = true;
+ }
+ return;
+ }
+
+ /* If SMA2 GPIO output map is all 1, it is not present.
+ * This indicates the firmware has fixed direction SMA pins.
+ */
+ reg = ioread32(&bp->sma_map2->gpio2);
+ if (reg == 0xffffffff) {
+ for (i = 0; i < 4; i++)
+ bp->sma[i].fixed_dir = true;
+ } else {
+ reg = ioread32(&bp->sma_map1->gpio1);
+ bp->sma[0].mode = reg & BIT(15) ? SMA_MODE_IN : SMA_MODE_OUT;
+ bp->sma[1].mode = reg & BIT(31) ? SMA_MODE_IN : SMA_MODE_OUT;
+
+ reg = ioread32(&bp->sma_map1->gpio2);
+ bp->sma[2].mode = reg & BIT(15) ? SMA_MODE_OUT : SMA_MODE_IN;
+ bp->sma[3].mode = reg & BIT(31) ? SMA_MODE_OUT : SMA_MODE_IN;
+ }
+}
+
+static int
+ptp_ocp_fb_set_pins(struct ptp_ocp *bp)
+{
+ struct ptp_pin_desc *config;
+ int i;
+
+ config = kzalloc(sizeof(*config) * 4, GFP_KERNEL);
+ if (!config)
+ return -ENOMEM;
+
+ for (i = 0; i < 4; i++) {
+ sprintf(config[i].name, "sma%d", i + 1);
+ config[i].index = i;
+ }
+
+ bp->ptp_info.n_pins = 4;
+ bp->ptp_info.pin_config = config;
+
+ return 0;
+}
+
/* 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;
+
bp->flash_start = 1024 * 4096;
+ bp->eeprom_map = fb_eeprom_map;
+ bp->fw_version = ioread32(&bp->image->version);
+ bp->attr_tbl = fb_timecard_groups;
+ bp->fw_cap = OCP_CAP_BASIC;
+
+ 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_tod_init(bp);
ptp_ocp_nmea_out_init(bp);
+ ptp_ocp_sma_init(bp);
+ ptp_ocp_signal_init(bp);
+
+ err = ptp_ocp_fb_set_pins(bp);
+ if (err)
+ return err;
return ptp_ocp_init_clock(bp);
}
@@ -1521,38 +2021,8 @@ __handle_signal_inputs(struct ptp_ocp *bp, u32 val)
* ANT4 == sma4 (out)
*/
-enum ptp_ocp_sma_mode {
- SMA_MODE_IN,
- SMA_MODE_OUT,
-};
-
-static struct ptp_ocp_sma_connector {
- enum ptp_ocp_sma_mode mode;
- bool fixed_mode;
- u16 default_out_idx;
-} ptp_ocp_sma_map[4] = {
- {
- .mode = SMA_MODE_IN,
- .fixed_mode = true,
- },
- {
- .mode = SMA_MODE_IN,
- .fixed_mode = true,
- },
- {
- .mode = SMA_MODE_OUT,
- .fixed_mode = true,
- .default_out_idx = 0, /* 10Mhz */
- },
- {
- .mode = SMA_MODE_OUT,
- .fixed_mode = true,
- .default_out_idx = 1, /* PHC */
- },
-};
-
static ssize_t
-ptp_ocp_show_output(u32 val, char *buf, int default_idx)
+ptp_ocp_show_output(u32 val, char *buf, int def_val)
{
const char *name;
ssize_t count;
@@ -1560,13 +2030,13 @@ ptp_ocp_show_output(u32 val, char *buf, int default_idx)
count = sysfs_emit(buf, "OUT: ");
name = ptp_ocp_select_name_from_val(ptp_ocp_sma_out, val);
if (!name)
- name = ptp_ocp_sma_out[default_idx].name;
+ name = ptp_ocp_select_name_from_val(ptp_ocp_sma_out, def_val);
count += sysfs_emit_at(buf, count, "%s\n", name);
return count;
}
static ssize_t
-ptp_ocp_show_inputs(u32 val, char *buf, const char *zero_in)
+ptp_ocp_show_inputs(u32 val, char *buf, int def_val)
{
const char *name;
ssize_t count;
@@ -1579,8 +2049,10 @@ ptp_ocp_show_inputs(u32 val, char *buf, const char *zero_in)
count += sysfs_emit_at(buf, count, "%s ", name);
}
}
- if (!val && zero_in)
- count += sysfs_emit_at(buf, count, "%s ", zero_in);
+ if (!val && def_val >= 0) {
+ name = ptp_ocp_select_name_from_val(ptp_ocp_sma_in, def_val);
+ count += sysfs_emit_at(buf, count, "%s ", name);
+ }
if (count)
count--;
count += sysfs_emit_at(buf, count, "\n");
@@ -1605,7 +2077,7 @@ sma_parse_inputs(const char *buf, enum ptp_ocp_sma_mode *mode)
idx = 0;
dir = *mode == SMA_MODE_IN ? 0 : 1;
- if (!strcasecmp("IN:", argv[idx])) {
+ if (!strcasecmp("IN:", argv[0])) {
dir = 0;
idx++;
}
@@ -1626,102 +2098,126 @@ 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, u32 val, char *buf,
- const char *zero_in)
+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 = &ptp_ocp_sma_map[sma_nr - 1];
+ struct ptp_ocp_sma_connector *sma = &bp->sma[sma_nr - 1];
+ u32 val;
+
+ val = ptp_ocp_sma_get(bp, sma_nr, sma->mode) & SMA_SELECT_MASK;
- if (sma->mode == SMA_MODE_IN)
- return ptp_ocp_show_inputs(val, buf, zero_in);
+ 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_output(val, buf, sma->default_out_idx);
+ return ptp_ocp_show_output(val, buf, default_out_val);
}
static ssize_t
sma1_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct ptp_ocp *bp = dev_get_drvdata(dev);
- u32 val;
- val = ioread32(&bp->sma->gpio1) & 0x3f;
- return ptp_ocp_sma_show(bp, 1, val, buf, ptp_ocp_sma_in[0].name);
+ return ptp_ocp_sma_show(bp, 1, buf, 0, 1);
}
static ssize_t
sma2_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct ptp_ocp *bp = dev_get_drvdata(dev);
- u32 val;
- val = (ioread32(&bp->sma->gpio1) >> 16) & 0x3f;
- return ptp_ocp_sma_show(bp, 2, val, buf, NULL);
+ return ptp_ocp_sma_show(bp, 2, buf, -1, 1);
}
static ssize_t
sma3_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct ptp_ocp *bp = dev_get_drvdata(dev);
- u32 val;
- val = ioread32(&bp->sma->gpio2) & 0x3f;
- return ptp_ocp_sma_show(bp, 3, val, buf, NULL);
+ return ptp_ocp_sma_show(bp, 3, buf, -1, 0);
}
static ssize_t
sma4_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct ptp_ocp *bp = dev_get_drvdata(dev);
- u32 val;
- val = (ioread32(&bp->sma->gpio2) >> 16) & 0x3f;
- return ptp_ocp_sma_show(bp, 4, val, buf, NULL);
+ return ptp_ocp_sma_show(bp, 4, buf, -1, 1);
}
static void
-ptp_ocp_sma_store_output(struct ptp_ocp *bp, u32 val, u32 shift)
+ptp_ocp_sma_store_output(struct ptp_ocp *bp, int sma_nr, u32 val)
{
+ u32 reg, mask, shift;
unsigned long flags;
- u32 gpio, mask;
+ 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);
- gpio = ioread32(&bp->sma->gpio2);
- gpio = (gpio & mask) | (val << shift);
+ reg = ioread32(gpio);
+ reg = (reg & mask) | (val << shift);
- __handle_signal_outputs(bp, gpio);
+ __handle_signal_outputs(bp, reg);
- iowrite32(gpio, &bp->sma->gpio2);
+ iowrite32(reg, gpio);
spin_unlock_irqrestore(&bp->lock, flags);
}
static void
-ptp_ocp_sma_store_inputs(struct ptp_ocp *bp, u32 val, u32 shift)
+ptp_ocp_sma_store_inputs(struct ptp_ocp *bp, int sma_nr, u32 val)
{
+ u32 reg, mask, shift;
unsigned long flags;
- u32 gpio, mask;
+ 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);
- gpio = ioread32(&bp->sma->gpio1);
- gpio = (gpio & mask) | (val << shift);
+ reg = ioread32(gpio);
+ reg = (reg & mask) | (val << shift);
- __handle_signal_inputs(bp, gpio);
+ __handle_signal_inputs(bp, reg);
- iowrite32(gpio, &bp->sma->gpio1);
+ iowrite32(reg, gpio);
spin_unlock_irqrestore(&bp->lock, flags);
}
-static ssize_t
-ptp_ocp_sma_store(struct ptp_ocp *bp, const char *buf, int sma_nr, u32 shift)
+static int
+ptp_ocp_sma_store(struct ptp_ocp *bp, const char *buf, int sma_nr)
{
- struct ptp_ocp_sma_connector *sma = &ptp_ocp_sma_map[sma_nr - 1];
+ struct ptp_ocp_sma_connector *sma = &bp->sma[sma_nr - 1];
enum ptp_ocp_sma_mode mode;
int val;
@@ -1730,18 +2226,35 @@ ptp_ocp_sma_store(struct ptp_ocp *bp, const char *buf, int sma_nr, u32 shift)
if (val < 0)
return val;
- if (mode != sma->mode && sma->fixed_mode)
+ if (sma->fixed_dir && (mode != sma->mode || val & SMA_DISABLE))
return -EOPNOTSUPP;
+ if (sma->fixed_fcn) {
+ if (val != ((sma_nr - 1) & 1))
+ return -EOPNOTSUPP;
+ return 0;
+ }
+
+ sma->disabled = !!(val & SMA_DISABLE);
+
if (mode != sma->mode) {
- pr_err("Mode changes not supported yet.\n");
- return -EOPNOTSUPP;
+ if (mode == SMA_MODE_IN)
+ ptp_ocp_sma_store_output(bp, sma_nr, 0);
+ else
+ ptp_ocp_sma_store_inputs(bp, sma_nr, 0);
+ sma->mode = mode;
}
- if (sma->mode == SMA_MODE_IN)
- ptp_ocp_sma_store_inputs(bp, val, shift);
+ if (!sma->fixed_dir)
+ val |= SMA_ENABLE; /* add enable bit */
+
+ if (sma->disabled)
+ val = 0;
+
+ if (mode == SMA_MODE_IN)
+ ptp_ocp_sma_store_inputs(bp, sma_nr, val);
else
- ptp_ocp_sma_store_output(bp, val, shift);
+ ptp_ocp_sma_store_output(bp, sma_nr, val);
return 0;
}
@@ -1753,7 +2266,7 @@ sma1_store(struct device *dev, struct device_attribute *attr,
struct ptp_ocp *bp = dev_get_drvdata(dev);
int err;
- err = ptp_ocp_sma_store(bp, buf, 1, 0);
+ err = ptp_ocp_sma_store(bp, buf, 1);
return err ? err : count;
}
@@ -1764,7 +2277,7 @@ sma2_store(struct device *dev, struct device_attribute *attr,
struct ptp_ocp *bp = dev_get_drvdata(dev);
int err;
- err = ptp_ocp_sma_store(bp, buf, 2, 16);
+ err = ptp_ocp_sma_store(bp, buf, 2);
return err ? err : count;
}
@@ -1775,7 +2288,7 @@ sma3_store(struct device *dev, struct device_attribute *attr,
struct ptp_ocp *bp = dev_get_drvdata(dev);
int err;
- err = ptp_ocp_sma_store(bp, buf, 3, 0);
+ err = ptp_ocp_sma_store(bp, buf, 3);
return err ? err : count;
}
@@ -1786,7 +2299,7 @@ sma4_store(struct device *dev, struct device_attribute *attr,
struct ptp_ocp *bp = dev_get_drvdata(dev);
int err;
- err = ptp_ocp_sma_store(bp, buf, 4, 16);
+ err = ptp_ocp_sma_store(bp, buf, 4);
return err ? err : count;
}
static DEVICE_ATTR_RW(sma1);
@@ -1810,13 +2323,263 @@ available_sma_outputs_show(struct device *dev,
}
static DEVICE_ATTR_RO(available_sma_outputs);
+#define EXT_ATTR_RO(_group, _name, _val) \
+ struct dev_ext_attribute dev_attr_##_group##_val##_##_name = \
+ { __ATTR_RO(_name), (void *)_val }
+#define EXT_ATTR_RW(_group, _name, _val) \
+ struct dev_ext_attribute dev_attr_##_group##_val##_##_name = \
+ { __ATTR_RW(_name), (void *)_val }
+#define to_ext_attr(x) container_of(x, struct dev_ext_attribute, attr)
+
+/* period [duty [phase [polarity]]] */
+static ssize_t
+signal_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct dev_ext_attribute *ea = to_ext_attr(attr);
+ struct ptp_ocp *bp = dev_get_drvdata(dev);
+ struct ptp_ocp_signal s = { };
+ int gen = (uintptr_t)ea->var;
+ int argc, err;
+ char **argv;
+
+ argv = argv_split(GFP_KERNEL, buf, &argc);
+ if (!argv)
+ return -ENOMEM;
+
+ err = -EINVAL;
+ s.duty = bp->signal[gen].duty;
+ s.phase = bp->signal[gen].phase;
+ s.period = bp->signal[gen].period;
+ s.polarity = bp->signal[gen].polarity;
+
+ switch (argc) {
+ case 4:
+ argc--;
+ err = kstrtobool(argv[argc], &s.polarity);
+ if (err)
+ goto out;
+ fallthrough;
+ case 3:
+ argc--;
+ err = kstrtou64(argv[argc], 0, &s.phase);
+ if (err)
+ goto out;
+ fallthrough;
+ case 2:
+ argc--;
+ err = kstrtoint(argv[argc], 0, &s.duty);
+ if (err)
+ goto out;
+ fallthrough;
+ case 1:
+ argc--;
+ err = kstrtou64(argv[argc], 0, &s.period);
+ if (err)
+ goto out;
+ break;
+ default:
+ goto out;
+ }
+
+ err = ptp_ocp_signal_set(bp, gen, &s);
+ if (err)
+ goto out;
+
+ err = ptp_ocp_signal_enable(bp->signal_out[gen], gen, s.period != 0);
+
+out:
+ argv_free(argv);
+ return err ? err : count;
+}
+
+static ssize_t
+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;
+ 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);
+
+ ts = ktime_to_timespec64(signal->start);
+ count += sysfs_emit_at(buf, count, " %ptT TAI\n", &ts);
+
+ return count;
+}
+static EXT_ATTR_RW(signal, signal, 0);
+static EXT_ATTR_RW(signal, signal, 1);
+static EXT_ATTR_RW(signal, signal, 2);
+static EXT_ATTR_RW(signal, signal, 3);
+
+static ssize_t
+duty_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);
+ int i = (uintptr_t)ea->var;
+
+ return sysfs_emit(buf, "%d\n", bp->signal[i].duty);
+}
+static EXT_ATTR_RO(signal, duty, 0);
+static EXT_ATTR_RO(signal, duty, 1);
+static EXT_ATTR_RO(signal, duty, 2);
+static EXT_ATTR_RO(signal, duty, 3);
+
+static ssize_t
+period_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);
+ int i = (uintptr_t)ea->var;
+
+ return sysfs_emit(buf, "%llu\n", bp->signal[i].period);
+}
+static EXT_ATTR_RO(signal, period, 0);
+static EXT_ATTR_RO(signal, period, 1);
+static EXT_ATTR_RO(signal, period, 2);
+static EXT_ATTR_RO(signal, period, 3);
+
+static ssize_t
+phase_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);
+ int i = (uintptr_t)ea->var;
+
+ return sysfs_emit(buf, "%llu\n", bp->signal[i].phase);
+}
+static EXT_ATTR_RO(signal, phase, 0);
+static EXT_ATTR_RO(signal, phase, 1);
+static EXT_ATTR_RO(signal, phase, 2);
+static EXT_ATTR_RO(signal, phase, 3);
+
+static ssize_t
+polarity_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);
+ int i = (uintptr_t)ea->var;
+
+ return sysfs_emit(buf, "%d\n", bp->signal[i].polarity);
+}
+static EXT_ATTR_RO(signal, polarity, 0);
+static EXT_ATTR_RO(signal, polarity, 1);
+static EXT_ATTR_RO(signal, polarity, 2);
+static EXT_ATTR_RO(signal, polarity, 3);
+
+static ssize_t
+running_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);
+ int i = (uintptr_t)ea->var;
+
+ return sysfs_emit(buf, "%d\n", bp->signal[i].running);
+}
+static EXT_ATTR_RO(signal, running, 0);
+static EXT_ATTR_RO(signal, running, 1);
+static EXT_ATTR_RO(signal, running, 2);
+static EXT_ATTR_RO(signal, running, 3);
+
+static ssize_t
+start_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);
+ int i = (uintptr_t)ea->var;
+ struct timespec64 ts;
+
+ ts = ktime_to_timespec64(bp->signal[i].start);
+ return sysfs_emit(buf, "%llu.%lu\n", ts.tv_sec, ts.tv_nsec);
+}
+static EXT_ATTR_RO(signal, start, 0);
+static EXT_ATTR_RO(signal, start, 1);
+static EXT_ATTR_RO(signal, start, 2);
+static EXT_ATTR_RO(signal, start, 3);
+
+static ssize_t
+seconds_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct dev_ext_attribute *ea = to_ext_attr(attr);
+ struct ptp_ocp *bp = dev_get_drvdata(dev);
+ int idx = (uintptr_t)ea->var;
+ u32 val;
+ int err;
+
+ err = kstrtou32(buf, 0, &val);
+ if (err)
+ return err;
+ if (val > 0xff)
+ return -EINVAL;
+
+ if (val)
+ val = (val << 8) | 0x1;
+
+ iowrite32(val, &bp->freq_in[idx]->ctrl);
+
+ return count;
+}
+
+static ssize_t
+seconds_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);
+ int idx = (uintptr_t)ea->var;
+ u32 val;
+
+ val = ioread32(&bp->freq_in[idx]->ctrl);
+ if (val & 1)
+ val = (val >> 8) & 0xff;
+ else
+ val = 0;
+
+ return sysfs_emit(buf, "%u\n", val);
+}
+static EXT_ATTR_RW(freq, seconds, 0);
+static EXT_ATTR_RW(freq, seconds, 1);
+static EXT_ATTR_RW(freq, seconds, 2);
+static EXT_ATTR_RW(freq, seconds, 3);
+
+static ssize_t
+frequency_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);
+ int idx = (uintptr_t)ea->var;
+ u32 val;
+
+ val = ioread32(&bp->freq_in[idx]->status);
+ if (val & FREQ_STATUS_ERROR)
+ return sysfs_emit(buf, "error\n");
+ if (val & FREQ_STATUS_OVERRUN)
+ return sysfs_emit(buf, "overrun\n");
+ if (val & FREQ_STATUS_VALID)
+ return sysfs_emit(buf, "%lu\n", val & FREQ_STATUS_MASK);
+ return 0;
+}
+static EXT_ATTR_RO(freq, frequency, 0);
+static EXT_ATTR_RO(freq, frequency, 1);
+static EXT_ATTR_RO(freq, frequency, 2);
+static EXT_ATTR_RO(freq, frequency, 3);
+
static ssize_t
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);
}
@@ -1974,7 +2737,122 @@ available_clock_sources_show(struct device *dev,
}
static DEVICE_ATTR_RO(available_clock_sources);
-static struct attribute *timecard_attrs[] = {
+static ssize_t
+clock_status_drift_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ptp_ocp *bp = dev_get_drvdata(dev);
+ u32 val;
+ int res;
+
+ val = ioread32(&bp->reg->status_drift);
+ res = (val & ~INT_MAX) ? -1 : 1;
+ res *= (val & INT_MAX);
+ return sysfs_emit(buf, "%d\n", res);
+}
+static DEVICE_ATTR_RO(clock_status_drift);
+
+static ssize_t
+clock_status_offset_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ptp_ocp *bp = dev_get_drvdata(dev);
+ u32 val;
+ int res;
+
+ val = ioread32(&bp->reg->status_offset);
+ res = (val & ~INT_MAX) ? -1 : 1;
+ res *= (val & INT_MAX);
+ return sysfs_emit(buf, "%d\n", res);
+}
+static DEVICE_ATTR_RO(clock_status_offset);
+
+static ssize_t
+tod_correction_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ptp_ocp *bp = dev_get_drvdata(dev);
+ u32 val;
+ int res;
+
+ val = ioread32(&bp->tod->adj_sec);
+ res = (val & ~INT_MAX) ? -1 : 1;
+ res *= (val & INT_MAX);
+ return sysfs_emit(buf, "%d\n", res);
+}
+
+static ssize_t
+tod_correction_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ptp_ocp *bp = dev_get_drvdata(dev);
+ unsigned long flags;
+ int err, res;
+ u32 val = 0;
+
+ err = kstrtos32(buf, 0, &res);
+ if (err)
+ return err;
+ if (res < 0) {
+ res *= -1;
+ val |= BIT(31);
+ }
+ val |= res;
+
+ spin_lock_irqsave(&bp->lock, flags);
+ iowrite32(val, &bp->tod->adj_sec);
+ spin_unlock_irqrestore(&bp->lock, flags);
+
+ return count;
+}
+static DEVICE_ATTR_RW(tod_correction);
+
+#define _DEVICE_SIGNAL_GROUP_ATTRS(_nr) \
+ static struct attribute *fb_timecard_signal##_nr##_attrs[] = { \
+ &dev_attr_signal##_nr##_signal.attr.attr, \
+ &dev_attr_signal##_nr##_duty.attr.attr, \
+ &dev_attr_signal##_nr##_phase.attr.attr, \
+ &dev_attr_signal##_nr##_period.attr.attr, \
+ &dev_attr_signal##_nr##_polarity.attr.attr, \
+ &dev_attr_signal##_nr##_running.attr.attr, \
+ &dev_attr_signal##_nr##_start.attr.attr, \
+ NULL, \
+ }
+
+#define DEVICE_SIGNAL_GROUP(_name, _nr) \
+ _DEVICE_SIGNAL_GROUP_ATTRS(_nr); \
+ static const struct attribute_group \
+ fb_timecard_signal##_nr##_group = { \
+ .name = #_name, \
+ .attrs = fb_timecard_signal##_nr##_attrs, \
+}
+
+DEVICE_SIGNAL_GROUP(gen1, 0);
+DEVICE_SIGNAL_GROUP(gen2, 1);
+DEVICE_SIGNAL_GROUP(gen3, 2);
+DEVICE_SIGNAL_GROUP(gen4, 3);
+
+#define _DEVICE_FREQ_GROUP_ATTRS(_nr) \
+ static struct attribute *fb_timecard_freq##_nr##_attrs[] = { \
+ &dev_attr_freq##_nr##_seconds.attr.attr, \
+ &dev_attr_freq##_nr##_frequency.attr.attr, \
+ NULL, \
+ }
+
+#define DEVICE_FREQ_GROUP(_name, _nr) \
+ _DEVICE_FREQ_GROUP_ATTRS(_nr); \
+ static const struct attribute_group \
+ fb_timecard_freq##_nr##_group = { \
+ .name = #_name, \
+ .attrs = fb_timecard_freq##_nr##_attrs, \
+}
+
+DEVICE_FREQ_GROUP(freq1, 0);
+DEVICE_FREQ_GROUP(freq2, 1);
+DEVICE_FREQ_GROUP(freq3, 2);
+DEVICE_FREQ_GROUP(freq4, 3);
+
+static struct attribute *fb_timecard_attrs[] = {
&dev_attr_serialnum.attr,
&dev_attr_gnss_sync.attr,
&dev_attr_clock_source.attr,
@@ -1985,38 +2863,119 @@ static struct attribute *timecard_attrs[] = {
&dev_attr_sma4.attr,
&dev_attr_available_sma_inputs.attr,
&dev_attr_available_sma_outputs.attr,
+ &dev_attr_clock_status_drift.attr,
+ &dev_attr_clock_status_offset.attr,
&dev_attr_irig_b_mode.attr,
&dev_attr_utc_tai_offset.attr,
&dev_attr_ts_window_adjust.attr,
+ &dev_attr_tod_correction.attr,
NULL,
};
-ATTRIBUTE_GROUPS(timecard);
+static const struct attribute_group fb_timecard_group = {
+ .attrs = fb_timecard_attrs,
+};
+static const struct ocp_attr_group fb_timecard_groups[] = {
+ { .cap = OCP_CAP_BASIC, .group = &fb_timecard_group },
+ { .cap = OCP_CAP_SIGNAL, .group = &fb_timecard_signal0_group },
+ { .cap = OCP_CAP_SIGNAL, .group = &fb_timecard_signal1_group },
+ { .cap = OCP_CAP_SIGNAL, .group = &fb_timecard_signal2_group },
+ { .cap = OCP_CAP_SIGNAL, .group = &fb_timecard_signal3_group },
+ { .cap = OCP_CAP_FREQ, .group = &fb_timecard_freq0_group },
+ { .cap = OCP_CAP_FREQ, .group = &fb_timecard_freq1_group },
+ { .cap = OCP_CAP_FREQ, .group = &fb_timecard_freq2_group },
+ { .cap = OCP_CAP_FREQ, .group = &fb_timecard_freq3_group },
+ { },
+};
-static const char *
-gpio_map(u32 gpio, u32 bit, const char *pri, const char *sec, const char *def)
+static void
+gpio_input_map(char *buf, struct ptp_ocp *bp, u16 map[][2], u16 bit,
+ const char *def)
{
- const char *ans;
+ int i;
- if (gpio & (1 << bit))
- ans = pri;
- else if (gpio & (1 << (bit + 16)))
- ans = sec;
- else
- ans = def;
- return ans;
+ for (i = 0; i < 4; i++) {
+ if (bp->sma[i].mode != SMA_MODE_IN)
+ continue;
+ if (map[i][0] & (1 << bit)) {
+ sprintf(buf, "sma%d", i + 1);
+ return;
+ }
+ }
+ if (!def)
+ def = "----";
+ strcpy(buf, def);
}
static void
-gpio_multi_map(char *buf, u32 gpio, u32 bit,
- const char *pri, const char *sec, const char *def)
+gpio_output_map(char *buf, struct ptp_ocp *bp, u16 map[][2], u16 bit)
{
char *ans = buf;
+ int i;
- strcpy(ans, def);
- if (gpio & (1 << bit))
- ans += sprintf(ans, "%s ", pri);
- if (gpio & (1 << (bit + 16)))
- ans += sprintf(ans, "%s ", sec);
+ strcpy(ans, "----");
+ for (i = 0; i < 4; i++) {
+ if (bp->sma[i].mode != SMA_MODE_OUT)
+ continue;
+ if (map[i][1] & (1 << bit))
+ ans += sprintf(ans, "sma%d ", i + 1);
+ }
+}
+
+static void
+_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];
+ 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",
+ label, on ? " ON" : "OFF",
+ signal->period, signal->duty, signal->phase,
+ signal->polarity);
+
+ val = ioread32(&reg->enable);
+ seq_printf(s, " [%x", val);
+ val = ioread32(&reg->status);
+ seq_printf(s, " %x]", val);
+
+ seq_printf(s, " start:%llu\n", signal->start);
+}
+
+static void
+_frequency_summary_show(struct seq_file *s, int nr,
+ struct frequency_reg __iomem *reg)
+{
+ char label[8];
+ bool on;
+ u32 val;
+
+ if (!reg)
+ return;
+
+ sprintf(label, "FREQ%d", nr + 1);
+ val = ioread32(&reg->ctrl);
+ on = val & 1;
+ val = (val >> 8) & 0xff;
+ seq_printf(s, "%7s: %s, sec:%u",
+ label,
+ on ? " ON" : "OFF",
+ val);
+
+ val = ioread32(&reg->status);
+ if (val & FREQ_STATUS_ERROR)
+ seq_printf(s, ", error");
+ if (val & FREQ_STATUS_OVERRUN)
+ seq_printf(s, ", overrun");
+ if (val & FREQ_STATUS_VALID)
+ seq_printf(s, ", freq %lu Hz", val & FREQ_STATUS_MASK);
+ seq_printf(s, " reg:%x\n", val);
}
static int
@@ -2024,40 +2983,72 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
{
struct device *dev = s->private;
struct ptp_system_timestamp sts;
- u32 sma_in, sma_out, ctrl, val;
struct ts_reg __iomem *ts_reg;
struct timespec64 ts;
struct ptp_ocp *bp;
- const char *src;
+ u16 sma_val[4][2];
+ char *src, *buf;
+ u32 ctrl, val;
bool on, map;
- char *buf;
+ int i;
buf = (char *)__get_free_page(GFP_KERNEL);
if (!buf)
return -ENOMEM;
bp = dev_get_drvdata(dev);
- sma_in = ioread32(&bp->sma->gpio1);
- sma_out = ioread32(&bp->sma->gpio2);
seq_printf(s, "%7s: /dev/ptp%d\n", "PTP", ptp_clock_index(bp->ptp));
+ if (bp->gnss_port != -1)
+ seq_printf(s, "%7s: /dev/ttyS%d\n", "GNSS1", bp->gnss_port);
+ if (bp->gnss2_port != -1)
+ seq_printf(s, "%7s: /dev/ttyS%d\n", "GNSS2", bp->gnss2_port);
+ if (bp->mac_port != -1)
+ seq_printf(s, "%7s: /dev/ttyS%d\n", "MAC", bp->mac_port);
+ if (bp->nmea_port != -1)
+ seq_printf(s, "%7s: /dev/ttyS%d\n", "NMEA", bp->nmea_port);
+
+ memset(sma_val, 0xff, sizeof(sma_val));
+ if (bp->sma_map1) {
+ u32 reg;
+
+ reg = ioread32(&bp->sma_map1->gpio1);
+ sma_val[0][0] = reg & 0xffff;
+ sma_val[1][0] = reg >> 16;
+
+ reg = ioread32(&bp->sma_map1->gpio2);
+ sma_val[2][1] = reg & 0xffff;
+ sma_val[3][1] = reg >> 16;
+
+ reg = ioread32(&bp->sma_map2->gpio1);
+ sma_val[2][0] = reg & 0xffff;
+ sma_val[3][0] = reg >> 16;
+
+ reg = ioread32(&bp->sma_map2->gpio2);
+ sma_val[0][1] = reg & 0xffff;
+ sma_val[1][1] = reg >> 16;
+ }
sma1_show(dev, NULL, buf);
- seq_printf(s, " sma1: %s", buf);
+ seq_printf(s, " sma1: %04x,%04x %s",
+ sma_val[0][0], sma_val[0][1], buf);
sma2_show(dev, NULL, buf);
- seq_printf(s, " sma2: %s", buf);
+ seq_printf(s, " sma2: %04x,%04x %s",
+ sma_val[1][0], sma_val[1][1], buf);
sma3_show(dev, NULL, buf);
- seq_printf(s, " sma3: %s", buf);
+ seq_printf(s, " sma3: %04x,%04x %s",
+ sma_val[2][0], sma_val[2][1], buf);
sma4_show(dev, NULL, buf);
- seq_printf(s, " sma4: %s", buf);
+ seq_printf(s, " sma4: %04x,%04x %s",
+ sma_val[3][0], sma_val[3][1], buf);
if (bp->ts0) {
ts_reg = bp->ts0->mem;
on = ioread32(&ts_reg->enable);
- src = "GNSS";
+ src = "GNSS1";
seq_printf(s, "%7s: %s, src: %s\n", "TS0",
on ? " ON" : "OFF", src);
}
@@ -2065,17 +3056,33 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
if (bp->ts1) {
ts_reg = bp->ts1->mem;
on = ioread32(&ts_reg->enable);
- src = gpio_map(sma_in, 2, "sma1", "sma2", "----");
+ gpio_input_map(buf, bp, sma_val, 2, NULL);
seq_printf(s, "%7s: %s, src: %s\n", "TS1",
- on ? " ON" : "OFF", src);
+ on ? " ON" : "OFF", buf);
}
if (bp->ts2) {
ts_reg = bp->ts2->mem;
on = ioread32(&ts_reg->enable);
- src = gpio_map(sma_in, 3, "sma1", "sma2", "----");
+ gpio_input_map(buf, bp, sma_val, 3, NULL);
seq_printf(s, "%7s: %s, src: %s\n", "TS2",
- on ? " ON" : "OFF", src);
+ on ? " ON" : "OFF", buf);
+ }
+
+ if (bp->ts3) {
+ ts_reg = bp->ts3->mem;
+ on = ioread32(&ts_reg->enable);
+ gpio_input_map(buf, bp, sma_val, 6, NULL);
+ seq_printf(s, "%7s: %s, src: %s\n", "TS3",
+ on ? " ON" : "OFF", buf);
+ }
+
+ if (bp->ts4) {
+ ts_reg = bp->ts4->mem;
+ on = ioread32(&ts_reg->enable);
+ gpio_input_map(buf, bp, sma_val, 7, NULL);
+ seq_printf(s, "%7s: %s, src: %s\n", "TS4",
+ on ? " ON" : "OFF", buf);
}
if (bp->pps) {
@@ -2083,7 +3090,7 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
src = "PHC";
on = ioread32(&ts_reg->enable);
map = !!(bp->pps_req_map & OCP_REQ_TIMESTAMP);
- seq_printf(s, "%7s: %s, src: %s\n", "TS3",
+ seq_printf(s, "%7s: %s, src: %s\n", "TS5",
on && map ? " ON" : "OFF", src);
map = !!(bp->pps_req_map & OCP_REQ_PPS);
@@ -2091,11 +3098,19 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
on && map ? " ON" : "OFF", src);
}
+ if (bp->fw_cap & OCP_CAP_SIGNAL)
+ for (i = 0; i < 4; i++)
+ _signal_summary_show(s, bp, i);
+
+ if (bp->fw_cap & OCP_CAP_FREQ)
+ for (i = 0; i < 4; i++)
+ _frequency_summary_show(s, i, bp->freq_in[i]);
+
if (bp->irig_out) {
ctrl = ioread32(&bp->irig_out->ctrl);
on = ctrl & IRIG_M_CTRL_ENABLE;
val = ioread32(&bp->irig_out->status);
- gpio_multi_map(buf, sma_out, 4, "sma3", "sma4", "----");
+ gpio_output_map(buf, bp, sma_val, 4);
seq_printf(s, "%7s: %s, error: %d, mode %d, out: %s\n", "IRIG",
on ? " ON" : "OFF", val, (ctrl >> 16), buf);
}
@@ -2103,15 +3118,15 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
if (bp->irig_in) {
on = ioread32(&bp->irig_in->ctrl) & IRIG_S_CTRL_ENABLE;
val = ioread32(&bp->irig_in->status);
- src = gpio_map(sma_in, 4, "sma1", "sma2", "----");
+ gpio_input_map(buf, bp, sma_val, 4, NULL);
seq_printf(s, "%7s: %s, error: %d, src: %s\n", "IRIG in",
- on ? " ON" : "OFF", val, src);
+ on ? " ON" : "OFF", val, buf);
}
if (bp->dcf_out) {
on = ioread32(&bp->dcf_out->ctrl) & DCF_M_CTRL_ENABLE;
val = ioread32(&bp->dcf_out->status);
- gpio_multi_map(buf, sma_out, 5, "sma3", "sma4", "----");
+ gpio_output_map(buf, bp, sma_val, 5);
seq_printf(s, "%7s: %s, error: %d, out: %s\n", "DCF",
on ? " ON" : "OFF", val, buf);
}
@@ -2119,9 +3134,9 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
if (bp->dcf_in) {
on = ioread32(&bp->dcf_in->ctrl) & DCF_S_CTRL_ENABLE;
val = ioread32(&bp->dcf_in->status);
- src = gpio_map(sma_in, 5, "sma1", "sma2", "----");
+ gpio_input_map(buf, bp, sma_val, 5, NULL);
seq_printf(s, "%7s: %s, error: %d, src: %s\n", "DCF in",
- on ? " ON" : "OFF", val, src);
+ on ? " ON" : "OFF", val, buf);
}
if (bp->nmea_out) {
@@ -2134,12 +3149,13 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
/* compute src for PPS1, used below. */
if (bp->pps_select) {
val = ioread32(&bp->pps_select->gpio1);
+ src = &buf[80];
if (val & 0x01)
- src = gpio_map(sma_in, 0, "sma1", "sma2", "----");
+ gpio_input_map(src, bp, sma_val, 0, NULL);
else if (val & 0x02)
src = "MAC";
else if (val & 0x04)
- src = "GNSS";
+ src = "GNSS1";
else
src = "----";
} else {
@@ -2172,8 +3188,8 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
/* reuses PPS1 src from earlier */
seq_printf(s, "MAC PPS1 src: %s\n", src);
- src = gpio_map(sma_in, 1, "sma1", "sma2", "GNSS2");
- seq_printf(s, "MAC PPS2 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;
@@ -2200,6 +3216,57 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
}
DEFINE_SHOW_ATTRIBUTE(ptp_ocp_summary);
+static int
+ptp_ocp_tod_status_show(struct seq_file *s, void *data)
+{
+ struct device *dev = s->private;
+ struct ptp_ocp *bp;
+ u32 val;
+ int idx;
+
+ bp = dev_get_drvdata(dev);
+
+ val = ioread32(&bp->tod->ctrl);
+ if (!(val & TOD_CTRL_ENABLE)) {
+ seq_printf(s, "TOD Slave disabled\n");
+ return 0;
+ }
+ seq_printf(s, "TOD Slave enabled, Control Register 0x%08X\n", val);
+
+ idx = val & TOD_CTRL_PROTOCOL ? 4 : 0;
+ idx += (val >> 16) & 3;
+ seq_printf(s, "Protocol %s\n", ptp_ocp_tod_proto_name(idx));
+
+ idx = (val >> TOD_CTRL_GNSS_SHIFT) & TOD_CTRL_GNSS_MASK;
+ seq_printf(s, "GNSS %s\n", ptp_ocp_tod_gnss_name(idx));
+
+ val = ioread32(&bp->tod->version);
+ seq_printf(s, "TOD Version %d.%d.%d\n",
+ val >> 24, (val >> 16) & 0xff, val & 0xffff);
+
+ val = ioread32(&bp->tod->status);
+ seq_printf(s, "Status register: 0x%08X\n", val);
+
+ val = ioread32(&bp->tod->adj_sec);
+ idx = (val & ~INT_MAX) ? -1 : 1;
+ idx *= (val & INT_MAX);
+ seq_printf(s, "Correction seconds: %d\n", idx);
+
+ val = ioread32(&bp->tod->utc_status);
+ seq_printf(s, "UTC status register: 0x%08X\n", val);
+ seq_printf(s, "UTC offset: %d valid:%d\n",
+ val & TOD_STATUS_UTC_MASK, val & TOD_STATUS_UTC_VALID ? 1 : 0);
+ seq_printf(s, "Leap second info valid:%d, Leap second announce %d\n",
+ val & TOD_STATUS_LEAP_VALID ? 1 : 0,
+ val & TOD_STATUS_LEAP_ANNOUNCE ? 1 : 0);
+
+ val = ioread32(&bp->tod->leap);
+ seq_printf(s, "Time to next leap second (in sec): %d\n", (s32) val);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(ptp_ocp_tod_status);
+
static struct dentry *ptp_ocp_debugfs_root;
static void
@@ -2211,6 +3278,9 @@ ptp_ocp_debugfs_add_device(struct ptp_ocp *bp)
bp->debug_root = d;
debugfs_create_file("summary", 0444, bp->debug_root,
&bp->dev, &ptp_ocp_summary_fops);
+ if (bp->tod)
+ debugfs_create_file("tod_status", 0444, bp->debug_root,
+ &bp->dev, &ptp_ocp_tod_status_fops);
}
static void
@@ -2317,6 +3387,7 @@ ptp_ocp_complete(struct ptp_ocp *bp)
{
struct pps_device *pps;
char buf[32];
+ int i, err;
if (bp->gnss_port != -1) {
sprintf(buf, "ttyS%d", bp->gnss_port);
@@ -2341,8 +3412,13 @@ ptp_ocp_complete(struct ptp_ocp *bp)
if (pps)
ptp_ocp_symlink(bp, pps->dev, "pps");
- if (device_add_groups(&bp->dev, timecard_groups))
- pr_err("device add groups failed\n");
+ for (i = 0; bp->attr_tbl[i].cap; i++) {
+ if (!(bp->attr_tbl[i].cap & bp->fw_cap))
+ continue;
+ err = sysfs_create_group(&bp->dev.kobj, bp->attr_tbl[i].group);
+ if (err)
+ return err;
+ }
ptp_ocp_debugfs_add_device(bp);
@@ -2389,20 +3465,15 @@ ptp_ocp_info(struct ptp_ocp *bp)
u32 reg;
ptp_ocp_phc_info(bp);
- if (bp->tod)
- ptp_ocp_tod_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);
@@ -2420,17 +3491,22 @@ static void
ptp_ocp_detach_sysfs(struct ptp_ocp *bp)
{
struct device *dev = &bp->dev;
+ int i;
sysfs_remove_link(&dev->kobj, "ttyGNSS");
sysfs_remove_link(&dev->kobj, "ttyMAC");
sysfs_remove_link(&dev->kobj, "ptp");
sysfs_remove_link(&dev->kobj, "pps");
- device_remove_groups(dev, timecard_groups);
+ if (bp->attr_tbl)
+ for (i = 0; bp->attr_tbl[i].cap; i++)
+ sysfs_remove_group(&dev->kobj, bp->attr_tbl[i].group);
}
static void
ptp_ocp_detach(struct ptp_ocp *bp)
{
+ int i;
+
ptp_ocp_debugfs_remove_device(bp);
ptp_ocp_detach_sysfs(bp);
if (timer_pending(&bp->watchdog))
@@ -2441,8 +3517,15 @@ ptp_ocp_detach(struct ptp_ocp *bp)
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);
+ for (i = 0; i < 4; i++)
+ if (bp->signal_out[i])
+ ptp_ocp_unregister_ext(bp->signal_out[i]);
if (bp->gnss_port != -1)
serial8250_unregister_port(bp->gnss_port);
if (bp->gnss2_port != -1)
@@ -2461,6 +3544,7 @@ ptp_ocp_detach(struct ptp_ocp *bp)
pci_free_irq_vectors(bp->pdev);
if (bp->ptp)
ptp_clock_unregister(bp->ptp);
+ kfree(bp->ptp_info.pin_config);
device_unregister(&bp->dev);
}
@@ -2480,7 +3564,7 @@ ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
err = pci_enable_device(pdev);
if (err) {
dev_err(&pdev->dev, "pci_enable_device\n");
- goto out_unregister;
+ goto out_free;
}
bp = devlink_priv(devlink);
@@ -2493,7 +3577,7 @@ ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
* allow this - if not all of the IRQ's are returned, skip the
* extra devices and just register the clock.
*/
- err = pci_alloc_irq_vectors(pdev, 1, 11, PCI_IRQ_MSI | PCI_IRQ_MSIX);
+ err = pci_alloc_irq_vectors(pdev, 1, 17, PCI_IRQ_MSI | PCI_IRQ_MSIX);
if (err < 0) {
dev_err(&pdev->dev, "alloc_irq_vectors err: %d\n", err);
goto out;
@@ -2526,7 +3610,7 @@ out:
pci_set_drvdata(pdev, NULL);
out_disable:
pci_disable_device(pdev);
-out_unregister:
+out_free:
devlink_free(devlink);
return err;
}
diff --git a/drivers/ptp/ptp_pch.c b/drivers/ptp/ptp_pch.c
index 8070f3fd98f0..7d4da9e605ef 100644
--- a/drivers/ptp/ptp_pch.c
+++ b/drivers/ptp/ptp_pch.c
@@ -10,9 +10,10 @@
#include <linux/device.h>
#include <linux/err.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
+#include <linux/io-64-nonatomic-hi-lo.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -100,7 +101,6 @@ struct pch_ts_regs {
#define PCH_ECS_ETH (1 << 0)
#define PCH_ECS_CAN (1 << 1)
-#define PCH_STATION_BYTES 6
#define PCH_IEEE1588_ETH (1 << 0)
#define PCH_IEEE1588_CAN (1 << 1)
@@ -115,8 +115,6 @@ struct pch_dev {
int exts0_enabled;
int exts1_enabled;
- u32 mem_base;
- u32 mem_size;
u32 irq;
struct pci_dev *pdev;
spinlock_t register_lock;
@@ -148,28 +146,15 @@ static inline void pch_eth_enable_set(struct pch_dev *chip)
static u64 pch_systime_read(struct pch_ts_regs __iomem *regs)
{
u64 ns;
- u32 lo, hi;
- lo = ioread32(&regs->systime_lo);
- hi = ioread32(&regs->systime_hi);
+ ns = ioread64_lo_hi(&regs->systime_lo);
- ns = ((u64) hi) << 32;
- ns |= lo;
- ns <<= TICKS_NS_SHIFT;
-
- return ns;
+ return ns << TICKS_NS_SHIFT;
}
static void pch_systime_write(struct pch_ts_regs __iomem *regs, u64 ns)
{
- u32 hi, lo;
-
- ns >>= TICKS_NS_SHIFT;
- hi = ns >> 32;
- lo = ns & 0xffffffff;
-
- iowrite32(lo, &regs->systime_lo);
- iowrite32(hi, &regs->systime_hi);
+ iowrite64_lo_hi(ns >> TICKS_NS_SHIFT, &regs->systime_lo);
}
static inline void pch_block_reset(struct pch_dev *chip)
@@ -235,16 +220,10 @@ u64 pch_rx_snap_read(struct pci_dev *pdev)
{
struct pch_dev *chip = pci_get_drvdata(pdev);
u64 ns;
- u32 lo, hi;
- lo = ioread32(&chip->regs->rx_snap_lo);
- hi = ioread32(&chip->regs->rx_snap_hi);
+ ns = ioread64_lo_hi(&chip->regs->rx_snap_lo);
- ns = ((u64) hi) << 32;
- ns |= lo;
- ns <<= TICKS_NS_SHIFT;
-
- return ns;
+ return ns << TICKS_NS_SHIFT;
}
EXPORT_SYMBOL(pch_rx_snap_read);
@@ -252,16 +231,10 @@ u64 pch_tx_snap_read(struct pci_dev *pdev)
{
struct pch_dev *chip = pci_get_drvdata(pdev);
u64 ns;
- u32 lo, hi;
-
- lo = ioread32(&chip->regs->tx_snap_lo);
- hi = ioread32(&chip->regs->tx_snap_hi);
- ns = ((u64) hi) << 32;
- ns |= lo;
- ns <<= TICKS_NS_SHIFT;
+ ns = ioread64_lo_hi(&chip->regs->tx_snap_lo);
- return ns;
+ return ns << TICKS_NS_SHIFT;
}
EXPORT_SYMBOL(pch_tx_snap_read);
@@ -292,8 +265,9 @@ static void pch_reset(struct pch_dev *chip)
*/
int pch_set_station_address(u8 *addr, struct pci_dev *pdev)
{
- s32 i;
struct pch_dev *chip = pci_get_drvdata(pdev);
+ bool valid;
+ u64 mac;
/* Verify the parameter */
if ((chip->regs == NULL) || addr == (u8 *)NULL) {
@@ -301,37 +275,15 @@ int pch_set_station_address(u8 *addr, struct pci_dev *pdev)
"invalid params returning PCH_INVALIDPARAM\n");
return PCH_INVALIDPARAM;
}
- /* For all station address bytes */
- for (i = 0; i < PCH_STATION_BYTES; i++) {
- u32 val;
- s32 tmp;
-
- tmp = hex_to_bin(addr[i * 3]);
- if (tmp < 0) {
- dev_err(&pdev->dev,
- "invalid params returning PCH_INVALIDPARAM\n");
- return PCH_INVALIDPARAM;
- }
- val = tmp * 16;
- tmp = hex_to_bin(addr[(i * 3) + 1]);
- if (tmp < 0) {
- dev_err(&pdev->dev,
- "invalid params returning PCH_INVALIDPARAM\n");
- return PCH_INVALIDPARAM;
- }
- val += tmp;
- /* Expects ':' separated addresses */
- if ((i < 5) && (addr[(i * 3) + 2] != ':')) {
- dev_err(&pdev->dev,
- "invalid params returning PCH_INVALIDPARAM\n");
- return PCH_INVALIDPARAM;
- }
- /* Ideally we should set the address only after validating
- entire string */
- dev_dbg(&pdev->dev, "invoking pch_station_set\n");
- iowrite32(val, &chip->regs->ts_st[i]);
+ valid = mac_pton(addr, (u8 *)&mac);
+ if (!valid) {
+ dev_err(&pdev->dev, "invalid params returning PCH_INVALIDPARAM\n");
+ return PCH_INVALIDPARAM;
}
+
+ dev_dbg(&pdev->dev, "invoking pch_station_set\n");
+ iowrite64_lo_hi(mac, &chip->regs->ts_st);
return 0;
}
EXPORT_SYMBOL(pch_set_station_address);
@@ -344,19 +296,16 @@ static irqreturn_t isr(int irq, void *priv)
struct pch_dev *pch_dev = priv;
struct pch_ts_regs __iomem *regs = pch_dev->regs;
struct ptp_clock_event event;
- u32 ack = 0, lo, hi, val;
+ u32 ack = 0, val;
val = ioread32(&regs->event);
if (val & PCH_TSE_SNS) {
ack |= PCH_TSE_SNS;
if (pch_dev->exts0_enabled) {
- hi = ioread32(&regs->asms_hi);
- lo = ioread32(&regs->asms_lo);
event.type = PTP_CLOCK_EXTTS;
event.index = 0;
- event.timestamp = ((u64) hi) << 32;
- event.timestamp |= lo;
+ event.timestamp = ioread64_hi_lo(&regs->asms_hi);
event.timestamp <<= TICKS_NS_SHIFT;
ptp_clock_event(pch_dev->ptp_clock, &event);
}
@@ -365,12 +314,9 @@ static irqreturn_t isr(int irq, void *priv)
if (val & PCH_TSE_SNM) {
ack |= PCH_TSE_SNM;
if (pch_dev->exts1_enabled) {
- hi = ioread32(&regs->amms_hi);
- lo = ioread32(&regs->amms_lo);
event.type = PTP_CLOCK_EXTTS;
event.index = 1;
- event.timestamp = ((u64) hi) << 32;
- event.timestamp |= lo;
+ event.timestamp = ioread64_hi_lo(&regs->asms_hi);
event.timestamp <<= TICKS_NS_SHIFT;
ptp_clock_event(pch_dev->ptp_clock, &event);
}
@@ -501,31 +447,12 @@ static const struct ptp_clock_info ptp_pch_caps = {
.enable = ptp_pch_enable,
};
-#define pch_suspend NULL
-#define pch_resume NULL
-
static void pch_remove(struct pci_dev *pdev)
{
struct pch_dev *chip = pci_get_drvdata(pdev);
+ free_irq(pdev->irq, chip);
ptp_clock_unregister(chip->ptp_clock);
- /* free the interrupt */
- if (pdev->irq != 0)
- free_irq(pdev->irq, chip);
-
- /* unmap the virtual IO memory space */
- if (chip->regs != NULL) {
- iounmap(chip->regs);
- chip->regs = NULL;
- }
- /* release the reserved IO memory space */
- if (chip->mem_base != 0) {
- release_mem_region(chip->mem_base, chip->mem_size);
- chip->mem_base = 0;
- }
- pci_disable_device(pdev);
- kfree(chip);
- dev_info(&pdev->dev, "complete\n");
}
static s32
@@ -535,50 +462,29 @@ pch_probe(struct pci_dev *pdev, const struct pci_device_id *id)
unsigned long flags;
struct pch_dev *chip;
- chip = kzalloc(sizeof(struct pch_dev), GFP_KERNEL);
+ chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
if (chip == NULL)
return -ENOMEM;
/* enable the 1588 pci device */
- ret = pci_enable_device(pdev);
+ ret = pcim_enable_device(pdev);
if (ret != 0) {
dev_err(&pdev->dev, "could not enable the pci device\n");
- goto err_pci_en;
+ return ret;
}
- chip->mem_base = pci_resource_start(pdev, IO_MEM_BAR);
- if (!chip->mem_base) {
+ ret = pcim_iomap_regions(pdev, BIT(IO_MEM_BAR), "1588_regs");
+ if (ret) {
dev_err(&pdev->dev, "could not locate IO memory address\n");
- ret = -ENODEV;
- goto err_pci_start;
- }
-
- /* retrieve the available length of the IO memory space */
- chip->mem_size = pci_resource_len(pdev, IO_MEM_BAR);
-
- /* allocate the memory for the device registers */
- if (!request_mem_region(chip->mem_base, chip->mem_size, "1588_regs")) {
- dev_err(&pdev->dev,
- "could not allocate register memory space\n");
- ret = -EBUSY;
- goto err_req_mem_region;
+ return ret;
}
/* get the virtual address to the 1588 registers */
- chip->regs = ioremap(chip->mem_base, chip->mem_size);
-
- if (!chip->regs) {
- dev_err(&pdev->dev, "Could not get virtual address\n");
- ret = -ENOMEM;
- goto err_ioremap;
- }
-
+ chip->regs = pcim_iomap_table(pdev)[IO_MEM_BAR];
chip->caps = ptp_pch_caps;
chip->ptp_clock = ptp_clock_register(&chip->caps, &pdev->dev);
- if (IS_ERR(chip->ptp_clock)) {
- ret = PTR_ERR(chip->ptp_clock);
- goto err_ptp_clock_reg;
- }
+ if (IS_ERR(chip->ptp_clock))
+ return PTR_ERR(chip->ptp_clock);
spin_lock_init(&chip->register_lock);
@@ -598,8 +504,7 @@ pch_probe(struct pci_dev *pdev, const struct pci_device_id *id)
pch_reset(chip);
iowrite32(DEFAULT_ADDEND, &chip->regs->addend);
- iowrite32(1, &chip->regs->trgt_lo);
- iowrite32(0, &chip->regs->trgt_hi);
+ iowrite64_lo_hi(1, &chip->regs->trgt_lo);
iowrite32(PCH_TSE_TTIPEND, &chip->regs->event);
pch_eth_enable_set(chip);
@@ -617,21 +522,7 @@ pch_probe(struct pci_dev *pdev, const struct pci_device_id *id)
err_req_irq:
ptp_clock_unregister(chip->ptp_clock);
-err_ptp_clock_reg:
- iounmap(chip->regs);
- chip->regs = NULL;
-err_ioremap:
- release_mem_region(chip->mem_base, chip->mem_size);
-
-err_req_mem_region:
- chip->mem_base = 0;
-
-err_pci_start:
- pci_disable_device(pdev);
-
-err_pci_en:
- kfree(chip);
dev_err(&pdev->dev, "probe failed(ret=0x%x)\n", ret);
return ret;
@@ -646,33 +537,13 @@ static const struct pci_device_id pch_ieee1588_pcidev_id[] = {
};
MODULE_DEVICE_TABLE(pci, pch_ieee1588_pcidev_id);
-static SIMPLE_DEV_PM_OPS(pch_pm_ops, pch_suspend, pch_resume);
-
static struct pci_driver pch_driver = {
.name = KBUILD_MODNAME,
.id_table = pch_ieee1588_pcidev_id,
.probe = pch_probe,
.remove = pch_remove,
- .driver.pm = &pch_pm_ops,
};
-
-static void __exit ptp_pch_exit(void)
-{
- pci_unregister_driver(&pch_driver);
-}
-
-static s32 __init ptp_pch_init(void)
-{
- s32 ret;
-
- /* register the driver with the pci core */
- ret = pci_register_driver(&pch_driver);
-
- return ret;
-}
-
-module_init(ptp_pch_init);
-module_exit(ptp_pch_exit);
+module_pci_driver(pch_driver);
module_param_string(station,
pch_param.station, sizeof(pch_param.station), 0444);
diff --git a/drivers/ptp/ptp_sysfs.c b/drivers/ptp/ptp_sysfs.c
index 41b92dc2f011..9233bfedeb17 100644
--- a/drivers/ptp/ptp_sysfs.c
+++ b/drivers/ptp/ptp_sysfs.c
@@ -14,7 +14,7 @@ static ssize_t clock_name_show(struct device *dev,
struct device_attribute *attr, char *page)
{
struct ptp_clock *ptp = dev_get_drvdata(dev);
- return snprintf(page, PAGE_SIZE-1, "%s\n", ptp->info->name);
+ return sysfs_emit(page, "%s\n", ptp->info->name);
}
static DEVICE_ATTR_RO(clock_name);
@@ -387,7 +387,7 @@ static ssize_t ptp_pin_show(struct device *dev, struct device_attribute *attr,
mutex_unlock(&ptp->pincfg_mux);
- return snprintf(page, PAGE_SIZE, "%u %u\n", func, chan);
+ return sysfs_emit(page, "%u %u\n", func, chan);
}
static ssize_t ptp_pin_store(struct device *dev, struct device_attribute *attr,
diff --git a/drivers/ptp/ptp_vclock.c b/drivers/ptp/ptp_vclock.c
index ab1d233173e1..cb179a3ea508 100644
--- a/drivers/ptp/ptp_vclock.c
+++ b/drivers/ptp/ptp_vclock.c
@@ -57,6 +57,30 @@ static int ptp_vclock_gettime(struct ptp_clock_info *ptp,
return 0;
}
+static int ptp_vclock_gettimex(struct ptp_clock_info *ptp,
+ struct timespec64 *ts,
+ struct ptp_system_timestamp *sts)
+{
+ struct ptp_vclock *vclock = info_to_vclock(ptp);
+ struct ptp_clock *pptp = vclock->pclock;
+ struct timespec64 pts;
+ unsigned long flags;
+ int err;
+ u64 ns;
+
+ err = pptp->info->gettimex64(pptp->info, &pts, sts);
+ if (err)
+ return err;
+
+ spin_lock_irqsave(&vclock->lock, flags);
+ ns = timecounter_cyc2time(&vclock->tc, timespec64_to_ns(&pts));
+ spin_unlock_irqrestore(&vclock->lock, flags);
+
+ *ts = ns_to_timespec64(ns);
+
+ return 0;
+}
+
static int ptp_vclock_settime(struct ptp_clock_info *ptp,
const struct timespec64 *ts)
{
@@ -71,6 +95,28 @@ static int ptp_vclock_settime(struct ptp_clock_info *ptp,
return 0;
}
+static int ptp_vclock_getcrosststamp(struct ptp_clock_info *ptp,
+ struct system_device_crosststamp *xtstamp)
+{
+ struct ptp_vclock *vclock = info_to_vclock(ptp);
+ struct ptp_clock *pptp = vclock->pclock;
+ unsigned long flags;
+ int err;
+ u64 ns;
+
+ err = pptp->info->getcrosststamp(pptp->info, xtstamp);
+ if (err)
+ return err;
+
+ spin_lock_irqsave(&vclock->lock, flags);
+ ns = timecounter_cyc2time(&vclock->tc, ktime_to_ns(xtstamp->device));
+ spin_unlock_irqrestore(&vclock->lock, flags);
+
+ xtstamp->device = ns_to_ktime(ns);
+
+ return 0;
+}
+
static long ptp_vclock_refresh(struct ptp_clock_info *ptp)
{
struct ptp_vclock *vclock = info_to_vclock(ptp);
@@ -84,11 +130,9 @@ static long ptp_vclock_refresh(struct ptp_clock_info *ptp)
static const struct ptp_clock_info ptp_vclock_info = {
.owner = THIS_MODULE,
.name = "ptp virtual clock",
- /* The maximum ppb value that long scaled_ppm can support */
- .max_adj = 32767999,
+ .max_adj = 500000000,
.adjfine = ptp_vclock_adjfine,
.adjtime = ptp_vclock_adjtime,
- .gettime64 = ptp_vclock_gettime,
.settime64 = ptp_vclock_settime,
.do_aux_work = ptp_vclock_refresh,
};
@@ -124,6 +168,12 @@ struct ptp_vclock *ptp_vclock_register(struct ptp_clock *pclock)
vclock->pclock = pclock;
vclock->info = ptp_vclock_info;
+ if (pclock->info->gettimex64)
+ vclock->info.gettimex64 = ptp_vclock_gettimex;
+ else
+ vclock->info.gettime64 = ptp_vclock_gettime;
+ if (pclock->info->getcrosststamp)
+ vclock->info.getcrosststamp = ptp_vclock_getcrosststamp;
vclock->cc = ptp_vclock_cc;
snprintf(vclock->info.name, PTP_CLOCK_NAME_LEN, "ptp%d_virt",