Skip to content

Commit

Permalink
ptp: ocp: add Adva timecard support
Browse files Browse the repository at this point in the history
Adding support for the Adva timecard.
The card uses different drivers to provide access to the
firmware SPI flash (Altera based).
Other parts of the code are the same and could be reused.

Signed-off-by: Sagi Maimon <maimon.sagi@gmail.com>
Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev>
Link: https://lore.kernel.org/r/20240205153046.3642-1-maimon.sagi@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Sagi Maimon authored and Jakub Kicinski committed Feb 9, 2024
1 parent 4bea747 commit ef61f55
Showing 1 changed file with 293 additions and 9 deletions.
302 changes: 293 additions & 9 deletions drivers/ptp/ptp_ocp.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
#define PCI_VENDOR_ID_OROLIA 0x1ad7
#define PCI_DEVICE_ID_OROLIA_ARTCARD 0xa000

#define PCI_VENDOR_ID_ADVA 0xad5a
#define PCI_DEVICE_ID_ADVA_TIMECARD 0x0400

static struct class timecard_class = {
.name = "timecard",
};
Expand Down Expand Up @@ -63,6 +66,13 @@ struct ocp_reg {
u32 status_drift;
};

struct ptp_ocp_servo_conf {
u32 servo_offset_p;
u32 servo_offset_i;
u32 servo_drift_p;
u32 servo_drift_i;
};

#define OCP_CTRL_ENABLE BIT(0)
#define OCP_CTRL_ADJUST_TIME BIT(1)
#define OCP_CTRL_ADJUST_OFFSET BIT(2)
Expand Down Expand Up @@ -397,10 +407,14 @@ static int ptp_ocp_sma_store(struct ptp_ocp *bp, const char *buf, int sma_nr);

static int ptp_ocp_art_board_init(struct ptp_ocp *bp, struct ocp_resource *r);

static int ptp_ocp_adva_board_init(struct ptp_ocp *bp, struct ocp_resource *r);

static const struct ocp_attr_group fb_timecard_groups[];

static const struct ocp_attr_group art_timecard_groups[];

static const struct ocp_attr_group adva_timecard_groups[];

struct ptp_ocp_eeprom_map {
u16 off;
u16 len;
Expand Down Expand Up @@ -700,6 +714,12 @@ static struct ocp_resource ocp_fb_resource[] = {
},
{
.setup = ptp_ocp_fb_board_init,
.extra = &(struct ptp_ocp_servo_conf) {
.servo_offset_p = 0x2000,
.servo_offset_i = 0x1000,
.servo_drift_p = 0,
.servo_drift_i = 0,
},
},
{ }
};
Expand Down Expand Up @@ -831,6 +851,170 @@ static struct ocp_resource ocp_art_resource[] = {
},
{
.setup = ptp_ocp_art_board_init,
.extra = &(struct ptp_ocp_servo_conf) {
.servo_offset_p = 0x2000,
.servo_offset_i = 0x1000,
.servo_drift_p = 0,
.servo_drift_i = 0,
},
},
{ }
};

static struct ocp_resource ocp_adva_resource[] = {
{
OCP_MEM_RESOURCE(reg),
.offset = 0x01000000, .size = 0x10000,
},
{
OCP_EXT_RESOURCE(ts0),
.offset = 0x01010000, .size = 0x10000, .irq_vec = 1,
.extra = &(struct ptp_ocp_ext_info) {
.index = 0,
.irq_fcn = ptp_ocp_ts_irq,
.enable = ptp_ocp_ts_enable,
},
},
{
OCP_EXT_RESOURCE(ts1),
.offset = 0x01020000, .size = 0x10000, .irq_vec = 2,
.extra = &(struct ptp_ocp_ext_info) {
.index = 1,
.irq_fcn = ptp_ocp_ts_irq,
.enable = ptp_ocp_ts_enable,
},
},
{
OCP_EXT_RESOURCE(ts2),
.offset = 0x01060000, .size = 0x10000, .irq_vec = 6,
.extra = &(struct ptp_ocp_ext_info) {
.index = 2,
.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 = 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_MEM_RESOURCE(pps_to_ext),
.offset = 0x01030000, .size = 0x10000,
},
{
OCP_MEM_RESOURCE(pps_to_clk),
.offset = 0x01040000, .size = 0x10000,
},
{
OCP_MEM_RESOURCE(tod),
.offset = 0x01050000, .size = 0x10000,
},
{
OCP_MEM_RESOURCE(image),
.offset = 0x00020000, .size = 0x1000,
},
{
OCP_MEM_RESOURCE(pps_select),
.offset = 0x00130000, .size = 0x1000,
},
{
OCP_MEM_RESOURCE(sma_map1),
.offset = 0x00140000, .size = 0x1000,
},
{
OCP_MEM_RESOURCE(sma_map2),
.offset = 0x00220000, .size = 0x1000,
},
{
OCP_SERIAL_RESOURCE(gnss_port),
.offset = 0x00160000 + 0x1000, .irq_vec = 3,
.extra = &(struct ptp_ocp_serial_port) {
.baud = 9600,
},
},
{
OCP_SERIAL_RESOURCE(mac_port),
.offset = 0x00180000 + 0x1000, .irq_vec = 5,
.extra = &(struct ptp_ocp_serial_port) {
.baud = 115200,
},
},
{
OCP_MEM_RESOURCE(freq_in[0]),
.offset = 0x01200000, .size = 0x10000,
},
{
OCP_MEM_RESOURCE(freq_in[1]),
.offset = 0x01210000, .size = 0x10000,
},
{
OCP_SPI_RESOURCE(spi_flash),
.offset = 0x00310400, .size = 0x10000, .irq_vec = 9,
.extra = &(struct ptp_ocp_flash_info) {
.name = "spi_altera", .pci_offset = 0,
.data_size = sizeof(struct altera_spi_platform_data),
.data = &(struct altera_spi_platform_data) {
.num_chipselect = 1,
.num_devices = 1,
.devices = &(struct spi_board_info) {
.modalias = "spi-nor",
},
},
},
},
{
OCP_I2C_RESOURCE(i2c_ctrl),
.offset = 0x150000, .size = 0x100, .irq_vec = 7,
.extra = &(struct ptp_ocp_i2c_info) {
.name = "ocores-i2c",
.fixed_rate = 50000000,
.data_size = sizeof(struct ocores_i2c_platform_data),
.data = &(struct ocores_i2c_platform_data) {
.clock_khz = 50000,
.bus_khz = 100,
.reg_io_width = 4, // 32-bit/4-byte
.reg_shift = 2, // 32-bit addressing
.num_devices = 2,
.devices = (struct i2c_board_info[]) {
{ I2C_BOARD_INFO("24c02", 0x50) },
{ I2C_BOARD_INFO("24mac402", 0x58),
.platform_data = "mac" },
},
},
},
},
{
.setup = ptp_ocp_adva_board_init,
.extra = &(struct ptp_ocp_servo_conf) {
.servo_offset_p = 0xc000,
.servo_offset_i = 0x1000,
.servo_drift_p = 0,
.servo_drift_i = 0,
},
},
{ }
};
Expand All @@ -839,6 +1023,7 @@ static const struct pci_device_id ptp_ocp_pcidev_id[] = {
{ PCI_DEVICE_DATA(FACEBOOK, TIMECARD, &ocp_fb_resource) },
{ PCI_DEVICE_DATA(CELESTICA, TIMECARD, &ocp_fb_resource) },
{ PCI_DEVICE_DATA(OROLIA, ARTCARD, &ocp_art_resource) },
{ PCI_DEVICE_DATA(ADVA, TIMECARD, &ocp_adva_resource) },
{ }
};
MODULE_DEVICE_TABLE(pci, ptp_ocp_pcidev_id);
Expand Down Expand Up @@ -917,6 +1102,30 @@ static const struct ocp_selector ptp_ocp_art_sma_out[] = {
{ }
};

static const struct ocp_selector ptp_ocp_adva_sma_in[] = {
{ .name = "10Mhz", .value = 0x0000, .frequency = 10000000},
{ .name = "PPS1", .value = 0x0001, .frequency = 1 },
{ .name = "PPS2", .value = 0x0002, .frequency = 1 },
{ .name = "TS1", .value = 0x0004, .frequency = 0 },
{ .name = "TS2", .value = 0x0008, .frequency = 0 },
{ .name = "FREQ1", .value = 0x0100, .frequency = 0 },
{ .name = "FREQ2", .value = 0x0200, .frequency = 0 },
{ .name = "None", .value = SMA_DISABLE, .frequency = 0 },
{ }
};

static const struct ocp_selector ptp_ocp_adva_sma_out[] = {
{ .name = "10Mhz", .value = 0x0000, .frequency = 10000000},
{ .name = "PHC", .value = 0x0001, .frequency = 1 },
{ .name = "MAC", .value = 0x0002, .frequency = 1 },
{ .name = "GNSS1", .value = 0x0004, .frequency = 1 },
{ .name = "GEN1", .value = 0x0040 },
{ .name = "GEN2", .value = 0x0080 },
{ .name = "GND", .value = 0x2000 },
{ .name = "VCC", .value = 0x4000 },
{ }
};

struct ocp_sma_op {
const struct ocp_selector *tbl[2];
void (*init)(struct ptp_ocp *bp);
Expand Down Expand Up @@ -1363,20 +1572,19 @@ ptp_ocp_estimate_pci_timing(struct ptp_ocp *bp)
}

static int
ptp_ocp_init_clock(struct ptp_ocp *bp)
ptp_ocp_init_clock(struct ptp_ocp *bp, struct ptp_ocp_servo_conf *servo_conf)
{
struct timespec64 ts;
u32 ctrl;

ctrl = OCP_CTRL_ENABLE;
iowrite32(ctrl, &bp->reg->ctrl);

/* NO DRIFT Correction */
/* offset_p:i 1/8, offset_i: 1/16, drift_p: 0, drift_i: 0 */
iowrite32(0x2000, &bp->reg->servo_offset_p);
iowrite32(0x1000, &bp->reg->servo_offset_i);
iowrite32(0, &bp->reg->servo_drift_p);
iowrite32(0, &bp->reg->servo_drift_i);
/* servo configuration */
iowrite32(servo_conf->servo_offset_p, &bp->reg->servo_offset_p);
iowrite32(servo_conf->servo_offset_i, &bp->reg->servo_offset_i);
iowrite32(servo_conf->servo_drift_p, &bp->reg->servo_drift_p);
iowrite32(servo_conf->servo_drift_p, &bp->reg->servo_drift_i);

/* latch servo values */
ctrl |= OCP_CTRL_ADJUST_SERVO;
Expand Down Expand Up @@ -2348,6 +2556,14 @@ static const struct ocp_sma_op ocp_fb_sma_op = {
.set_output = ptp_ocp_sma_fb_set_output,
};

static const struct ocp_sma_op ocp_adva_sma_op = {
.tbl = { ptp_ocp_adva_sma_in, ptp_ocp_adva_sma_out },
.init = ptp_ocp_sma_fb_init,
.get = ptp_ocp_sma_fb_get,
.set_inputs = ptp_ocp_sma_fb_set_inputs,
.set_output = ptp_ocp_sma_fb_set_output,
};

static int
ptp_ocp_set_pins(struct ptp_ocp *bp)
{
Expand Down Expand Up @@ -2427,7 +2643,7 @@ ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
return err;
ptp_ocp_sma_init(bp);

return ptp_ocp_init_clock(bp);
return ptp_ocp_init_clock(bp, r->extra);
}

static bool
Expand Down Expand Up @@ -2589,7 +2805,44 @@ ptp_ocp_art_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
if (err)
return err;

return ptp_ocp_init_clock(bp);
return ptp_ocp_init_clock(bp, r->extra);
}

/* ADVA specific board initializers; last "resource" registered. */
static int
ptp_ocp_adva_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
{
int err;
u32 version;

bp->flash_start = 0xA00000;
bp->eeprom_map = fb_eeprom_map;
bp->sma_op = &ocp_adva_sma_op;

version = ioread32(&bp->image->version);
/* if lower 16 bits are empty, this is the fw loader. */
if ((version & 0xffff) == 0) {
version = version >> 16;
bp->fw_loader = true;
}
bp->fw_tag = 3;
bp->fw_version = version & 0xffff;
bp->fw_cap = OCP_CAP_BASIC | OCP_CAP_SIGNAL | OCP_CAP_FREQ;

ptp_ocp_tod_init(bp);
ptp_ocp_nmea_out_init(bp);
ptp_ocp_signal_init(bp);

err = ptp_ocp_attr_group_add(bp, adva_timecard_groups);
if (err)
return err;

err = ptp_ocp_set_pins(bp);
if (err)
return err;
ptp_ocp_sma_init(bp);

return ptp_ocp_init_clock(bp, r->extra);
}

static ssize_t
Expand Down Expand Up @@ -3564,6 +3817,37 @@ static const struct ocp_attr_group art_timecard_groups[] = {
{ },
};

static struct attribute *adva_timecard_attrs[] = {
&dev_attr_serialnum.attr,
&dev_attr_gnss_sync.attr,
&dev_attr_clock_source.attr,
&dev_attr_available_clock_sources.attr,
&dev_attr_sma1.attr,
&dev_attr_sma2.attr,
&dev_attr_sma3.attr,
&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_ts_window_adjust.attr,
&dev_attr_tod_correction.attr,
NULL,
};

static const struct attribute_group adva_timecard_group = {
.attrs = adva_timecard_attrs,
};

static const struct ocp_attr_group adva_timecard_groups[] = {
{ .cap = OCP_CAP_BASIC, .group = &adva_timecard_group },
{ .cap = OCP_CAP_SIGNAL, .group = &fb_timecard_signal0_group },
{ .cap = OCP_CAP_SIGNAL, .group = &fb_timecard_signal1_group },
{ .cap = OCP_CAP_FREQ, .group = &fb_timecard_freq0_group },
{ .cap = OCP_CAP_FREQ, .group = &fb_timecard_freq1_group },
{ },
};

static void
gpio_input_map(char *buf, struct ptp_ocp *bp, u16 map[][2], u16 bit,
const char *def)
Expand Down

0 comments on commit ef61f55

Please sign in to comment.