/**
 * Convert nanosecond based time to setting used in the
 * boot bus timing register, based on timing multiple
 */
static unsigned int ns_to_tim_reg(unsigned int tim_mult, unsigned int nsecs)
{
	unsigned int val;

	/*
	 * Compute # of eclock periods to get desired duration in
	 * nanoseconds.
	 */
	val = DIV_ROUND_UP(nsecs * (octeon_get_io_clock_rate() / 1000000),
			  1000 * tim_mult);

	return val;
}
static void __init octeon_uart_set_common(struct plat_serial8250_port *p)
{
	p->flags = ASYNC_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
	p->type = PORT_OCTEON;
	p->iotype = UPIO_MEM;
	p->regshift = 3;	/* I/O addresses are every 8 bytes */
	if (octeon_is_simulation())
		/* Make simulator output fast*/
		p->uartclk = 115200 * 16;
	else
		p->uartclk = octeon_get_io_clock_rate();
	p->serial_in = octeon_serial_in;
	p->serial_out = octeon_serial_out;
}
Exemple #3
0
static void init_latency_info(struct latency_info *li, int startup)
{
	/* interval in milli seconds after which the interrupt will
	 * be triggered
	 */
	int interval = 1;

	if (startup) {
		/* Calculating by the amounts io clock and cpu clock would
		 *  increment in interval amount of ms
		 */
		li->io_interval = (octeon_get_io_clock_rate() * interval) / 1000;
		li->cpu_interval = (octeon_get_clock_rate() * interval) / 1000;
	}
	li->timer_start1 = 0;
	li->timer_start2 = 0;
	li->max_latency = 0;
	li->min_latency = (u64)-1;
	li->latency_sum = 0;
	li->interrupt_cnt = 0;
}
Exemple #4
0
/**
 * User is reading /proc/octeon_info
 *
 * @param m
 * @param v
 * @return
 */
static int octeon_info_show(struct seq_file *m, void *v)
{

	seq_printf(m, "processor_id:        0x%x\n", read_c0_prid());
	seq_printf(m, "boot_flags:          0x%x\n", octeon_bootinfo->flags);
	seq_printf(m, "dram_size:           %u\n", octeon_bootinfo->dram_size);
	seq_printf(m, "phy_mem_desc_addr:   0x%x\n",
		   octeon_bootinfo->phy_mem_desc_addr);
	seq_printf(m, "eclock_hz:           %u\n", octeon_bootinfo->eclock_hz);
	seq_printf(m, "io_clock_hz:         %llu\n", octeon_get_io_clock_rate());
	seq_printf(m, "dclock_hz:           %u\n", octeon_bootinfo->dclock_hz);
	seq_printf(m, "board_type:          %u\n", octeon_bootinfo->board_type);
	seq_printf(m, "board_rev_major:     %u\n",
		   octeon_bootinfo->board_rev_major);
	seq_printf(m, "board_rev_minor:     %u\n",
		   octeon_bootinfo->board_rev_minor);
	seq_printf(m, "board_serial_number: %s\n",
		   octeon_bootinfo->board_serial_number);
	seq_printf(m, "mac_addr_base:       %02x:%02x:%02x:%02x:%02x:%02x\n",
		   (int) octeon_bootinfo->mac_addr_base[0],
		   (int) octeon_bootinfo->mac_addr_base[1],
		   (int) octeon_bootinfo->mac_addr_base[2],
		   (int) octeon_bootinfo->mac_addr_base[3],
		   (int) octeon_bootinfo->mac_addr_base[4],
		   (int) octeon_bootinfo->mac_addr_base[5]);
	seq_printf(m, "mac_addr_count:      %u\n",
		   octeon_bootinfo->mac_addr_count);
#if CONFIG_CAVIUM_RESERVE32
	seq_printf(m, "32bit_shared_mem_base: 0x%lx\n",
		   (long int) octeon_reserve32_memory);
	seq_printf(m, "32bit_shared_mem_size: 0x%x\n",
		   (long int) octeon_reserve32_memory ? CONFIG_CAVIUM_RESERVE32 << 20 : 0);
#else
	seq_printf(m, "32bit_shared_mem_base: 0x%lx\n", 0ul);
	seq_printf(m, "32bit_shared_mem_size: 0x%x\n", 0);
#endif
	return 0;
}
Exemple #5
0
static int octeon_i2c_probe(struct platform_device *pdev)
{
	int irq, result = 0;
	struct octeon_i2c *i2c;
	struct resource *res_mem;

	/* All adaptors have an irq.  */
	irq = platform_get_irq(pdev, 0);
	if (irq < 0)
		return irq;

	i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
	if (!i2c) {
		dev_err(&pdev->dev, "kzalloc failed\n");
		result = -ENOMEM;
		goto out;
	}
	i2c->dev = &pdev->dev;

	res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);

	if (res_mem == NULL) {
		dev_err(i2c->dev, "found no memory resource\n");
		result = -ENXIO;
		goto out;
	}
	i2c->twsi_phys = res_mem->start;
	i2c->regsize = resource_size(res_mem);

	/*
	 * "clock-rate" is a legacy binding, the official binding is
	 * "clock-frequency".  Try the official one first and then
	 * fall back if it doesn't exist.
	 */
	if (of_property_read_u32(pdev->dev.of_node,
				 "clock-frequency", &i2c->twsi_freq) &&
	    of_property_read_u32(pdev->dev.of_node,
				 "clock-rate", &i2c->twsi_freq)) {
		dev_err(i2c->dev,
			"no I2C 'clock-rate' or 'clock-frequency' property\n");
		result = -ENXIO;
		goto out;
	}

	i2c->sys_freq = octeon_get_io_clock_rate();

	if (!devm_request_mem_region(&pdev->dev, i2c->twsi_phys, i2c->regsize,
				      res_mem->name)) {
		dev_err(i2c->dev, "request_mem_region failed\n");
		goto out;
	}
	i2c->twsi_base = devm_ioremap(&pdev->dev, i2c->twsi_phys, i2c->regsize);

	init_waitqueue_head(&i2c->queue);

	i2c->irq = irq;

	result = devm_request_irq(&pdev->dev, i2c->irq,
				  octeon_i2c_isr, 0, DRV_NAME, i2c);
	if (result < 0) {
		dev_err(i2c->dev, "failed to attach interrupt\n");
		goto out;
	}

	result = octeon_i2c_initlowlevel(i2c);
	if (result) {
		dev_err(i2c->dev, "init low level failed\n");
		goto  out;
	}

	result = octeon_i2c_setclock(i2c);
	if (result) {
		dev_err(i2c->dev, "clock init failed\n");
		goto  out;
	}

	i2c->adap = octeon_i2c_ops;
	i2c->adap.dev.parent = &pdev->dev;
	i2c->adap.dev.of_node = pdev->dev.of_node;
	i2c_set_adapdata(&i2c->adap, i2c);
	platform_set_drvdata(pdev, i2c);

	result = i2c_add_adapter(&i2c->adap);
	if (result < 0) {
		dev_err(i2c->dev, "failed to add adapter\n");
		goto fail_add;
	}
	dev_info(i2c->dev, "version %s\n", DRV_VERSION);

	of_i2c_register_devices(&i2c->adap);

	return 0;

fail_add:
	platform_set_drvdata(pdev, NULL);
out:
	return result;
};
Exemple #6
0
void octeon2_usb_clocks_start(struct device *dev)
{
	u64 div;
	union cvmx_uctlx_if_ena if_ena;
	union cvmx_uctlx_clk_rst_ctl clk_rst_ctl;
	union cvmx_uctlx_uphy_portx_ctl_status port_ctl_status;
	struct device_node *uctl_node;
	u32 clock_rate = 12000000;
	bool is_crystal_clock = false;
	int i;
	unsigned long io_clk_64_to_ns;


	mutex_lock(&octeon2_usb_clocks_mutex);

	octeon2_usb_clock_start_cnt++;
	if (octeon2_usb_clock_start_cnt != 1)
		goto exit;

	io_clk_64_to_ns = 64000000000ull / octeon_get_io_clock_rate();

	if (dev->of_node) {
		const char *clock_type;

		uctl_node = of_get_parent(dev->of_node);
		if (!uctl_node) {
			pr_err("No UCTL device node\n");
			goto exit;
		}
		i = of_property_read_u32(uctl_node,
					 "refclk-frequency", &clock_rate);
		if (i) {
			pr_err("No UCTL \"refclk-frequency\"\n");
			goto exit;
		}
		i = of_property_read_string(uctl_node,
					    "refclk-type", &clock_type);

		if (!i && strcmp("crystal", clock_type) == 0)
			is_crystal_clock = true;
	}

	/*
	 * Step 1: Wait for voltages stable.  That surely happened
	 * before starting the kernel.
	 *
	 * Step 2: Enable  SCLK of UCTL by writing UCTL0_IF_ENA[EN] = 1
	 */
	if_ena.u64 = 0;
	if_ena.s.en = 1;
	cvmx_write_csr(CVMX_UCTLX_IF_ENA(0), if_ena.u64);

	for (i = 0; i <= 1; i++) {
		port_ctl_status.u64 =
			cvmx_read_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0));
		/* Set txvreftune to 15 to obtain compliant 'eye' diagram. */
		port_ctl_status.s.txvreftune = 15;
		port_ctl_status.s.txrisetune = 1;
		port_ctl_status.s.txpreemphasistune = 1;
		cvmx_write_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0),
			       port_ctl_status.u64);
	}

	/* Step 3: Configure the reference clock, PHY, and HCLK */
	clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0));

	/*
	 * If the UCTL looks like it has already been started, skip
	 * the initialization, otherwise bus errors are obtained.
	 */
	if (clk_rst_ctl.s.hrst)
		goto end_clock;
	/* 3a */
	clk_rst_ctl.s.p_por = 1;
	clk_rst_ctl.s.hrst = 0;
	clk_rst_ctl.s.p_prst = 0;
	clk_rst_ctl.s.h_clkdiv_rst = 0;
	clk_rst_ctl.s.o_clkdiv_rst = 0;
	clk_rst_ctl.s.h_clkdiv_en = 0;
	clk_rst_ctl.s.o_clkdiv_en = 0;
	cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);

	/* 3b */
	clk_rst_ctl.s.p_refclk_sel = is_crystal_clock ? 0 : 1;
	switch (clock_rate) {
	default:
		pr_err("Invalid UCTL clock rate of %u, using 12000000 instead\n",
			clock_rate);
		/* Fall through */
	case 12000000:
		clk_rst_ctl.s.p_refclk_div = 0;
		break;
	case 24000000:
		clk_rst_ctl.s.p_refclk_div = 1;
		break;
	case 48000000:
		clk_rst_ctl.s.p_refclk_div = 2;
		break;
	}
	cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);

	/* 3c */
	div = octeon_get_io_clock_rate() / 130000000ull;

	switch (div) {
	case 0:
		div = 1;
		break;
	case 1:
	case 2:
	case 3:
	case 4:
		break;
	case 5:
		div = 4;
		break;
	case 6:
	case 7:
		div = 6;
		break;
	case 8:
	case 9:
	case 10:
	case 11:
		div = 8;
		break;
	default:
		div = 12;
		break;
	}
	clk_rst_ctl.s.h_div = div;
	cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
	/* Read it back, */
	clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0));
	clk_rst_ctl.s.h_clkdiv_en = 1;
	cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
	/* 3d */
	clk_rst_ctl.s.h_clkdiv_rst = 1;
	cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);

	/* 3e: delay 64 io clocks */
	ndelay(io_clk_64_to_ns);

	/*
	 * Step 4: Program the power-on reset field in the UCTL
	 * clock-reset-control register.
	 */
	clk_rst_ctl.s.p_por = 0;
	cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);

	/* Step 5:    Wait 3 ms for the PHY clock to start. */
	mdelay(3);

	/* Steps 6..9 for ATE only, are skipped. */

	/* Step 10: Configure the OHCI_CLK48 and OHCI_CLK12 clocks. */
	/* 10a */
	clk_rst_ctl.s.o_clkdiv_rst = 1;
	cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);

	/* 10b */
	clk_rst_ctl.s.o_clkdiv_en = 1;
	cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);

	/* 10c */
	ndelay(io_clk_64_to_ns);

	/*
	 * Step 11: Program the PHY reset field:
	 * UCTL0_CLK_RST_CTL[P_PRST] = 1
	 */
	clk_rst_ctl.s.p_prst = 1;
	cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);

	/* Step 11b */
	udelay(1);

	/* Step 11c */
	clk_rst_ctl.s.p_prst = 0;
	cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);

	/* Step 11d */
	mdelay(1);

	/* Step 11e */
	clk_rst_ctl.s.p_prst = 1;
	cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);

	/* Step 12: Wait 1 uS. */
	udelay(1);

	/* Step 13: Program the HRESET_N field: UCTL0_CLK_RST_CTL[HRST] = 1 */
	clk_rst_ctl.s.hrst = 1;
	cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);

end_clock:
	/* Set uSOF cycle period to 60,000 bits. */
	cvmx_write_csr(CVMX_UCTLX_EHCI_FLA(0), 0x20ull);

	octeon_error_tree_enable(CVMX_ERROR_GROUP_USB, -1);
exit:
	mutex_unlock(&octeon2_usb_clocks_mutex);
}
Exemple #7
0
static int octeon_mgmt_ioctl_hwtstamp(struct net_device *netdev,
				      struct ifreq *rq, int cmd)
{
	struct octeon_mgmt *p = netdev_priv(netdev);
	struct hwtstamp_config config;
	union cvmx_mio_ptp_clock_cfg ptp;
	union cvmx_agl_gmx_rxx_frm_ctl rxx_frm_ctl;
	bool have_hw_timestamps = false;

	if (copy_from_user(&config, rq->ifr_data, sizeof(config)))
		return -EFAULT;

	if (config.flags) /* reserved for future extensions */
		return -EINVAL;

	/* Check the status of hardware for tiemstamps */
	if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) {
		/* Get the current state of the PTP clock */
		ptp.u64 = cvmx_read_csr(CVMX_MIO_PTP_CLOCK_CFG);
		if (!ptp.s.ext_clk_en) {
			/* The clock has not been configured to use an
			 * external source.  Program it to use the main clock
			 * reference.
			 */
			u64 clock_comp = (NSEC_PER_SEC << 32) /	octeon_get_io_clock_rate();
			if (!ptp.s.ptp_en)
				cvmx_write_csr(CVMX_MIO_PTP_CLOCK_COMP, clock_comp);
			pr_info("PTP Clock: Using sclk reference at %lld Hz\n",
				(NSEC_PER_SEC << 32) / clock_comp);
		} else {
			/* The clock is already programmed to use a GPIO */
			u64 clock_comp = cvmx_read_csr(CVMX_MIO_PTP_CLOCK_COMP);
			pr_info("PTP Clock: Using GPIO %d at %lld Hz\n",
				ptp.s.ext_clk_in,
				(NSEC_PER_SEC << 32) / clock_comp);
		}

		/* Enable the clock if it wasn't done already */
		if (!ptp.s.ptp_en) {
			ptp.s.ptp_en = 1;
			cvmx_write_csr(CVMX_MIO_PTP_CLOCK_CFG, ptp.u64);
		}
		have_hw_timestamps = true;
	}

	if (!have_hw_timestamps)
		return -EINVAL;

	switch (config.tx_type) {
	case HWTSTAMP_TX_OFF:
	case HWTSTAMP_TX_ON:
		break;
	default:
		return -ERANGE;
	}

	switch (config.rx_filter) {
	case HWTSTAMP_FILTER_NONE:
		p->has_rx_tstamp = false;
		rxx_frm_ctl.u64 = cvmx_read_csr(p->agl + AGL_GMX_RX_FRM_CTL);
		rxx_frm_ctl.s.ptp_mode = 0;
		cvmx_write_csr(p->agl + AGL_GMX_RX_FRM_CTL, rxx_frm_ctl.u64);
		break;
	case HWTSTAMP_FILTER_ALL:
	case HWTSTAMP_FILTER_SOME:
	case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
	case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
	case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
	case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
	case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
	case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
	case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
	case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
	case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
	case HWTSTAMP_FILTER_PTP_V2_EVENT:
	case HWTSTAMP_FILTER_PTP_V2_SYNC:
	case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
		p->has_rx_tstamp = have_hw_timestamps;
		config.rx_filter = HWTSTAMP_FILTER_ALL;
		if (p->has_rx_tstamp) {
			rxx_frm_ctl.u64 = cvmx_read_csr(p->agl + AGL_GMX_RX_FRM_CTL);
			rxx_frm_ctl.s.ptp_mode = 1;
			cvmx_write_csr(p->agl + AGL_GMX_RX_FRM_CTL, rxx_frm_ctl.u64);
		}
		break;
	default:
		return -ERANGE;
	}

	if (copy_to_user(rq->ifr_data, &config, sizeof(config)))
		return -EFAULT;

	return 0;
}
/**
 * cvm_oct_ioctl_hwtstamp - IOCTL support for timestamping
 * @dev:    Device to change
 * @rq:     the request
 * @cmd:    the command
 *
 * Returns Zero on success
 */
static int cvm_oct_ioctl_hwtstamp(struct net_device *dev,
	struct ifreq *rq, int cmd)
{
	struct octeon_ethernet *priv = netdev_priv(dev);
	struct hwtstamp_config config;
	union cvmx_mio_ptp_clock_cfg ptp;
	int have_hw_timestamps = 0;

	if (copy_from_user(&config, rq->ifr_data, sizeof(config)))
		return -EFAULT;

	if (config.flags) /* reserved for future extensions */
		return -EINVAL;

	/* Check the status of hardware for tiemstamps */
	if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) {
		/* Write TX timestamp into word 4 */
		cvmx_write_csr(CVMX_PKO_REG_TIMESTAMP, 4);
		/* Get the current state of the PTP clock */
		ptp.u64 = cvmx_read_csr(CVMX_MIO_PTP_CLOCK_CFG);
		if (!ptp.s.ext_clk_en) {
			/*
			 * The clock has not been configured to use an
			 * external source.  Program it to use the main clock
			 * reference.
			 */
			unsigned long long clock_comp = (NSEC_PER_SEC << 32) /
				octeon_get_io_clock_rate();
			cvmx_write_csr(CVMX_MIO_PTP_CLOCK_COMP, clock_comp);
			pr_info("PTP Clock: Using sclk reference at %lld Hz\n",
				(NSEC_PER_SEC << 32) / clock_comp);
		} else {
			/* The clock is already programmed to use a GPIO */
			unsigned long long clock_comp = cvmx_read_csr(
				CVMX_MIO_PTP_CLOCK_COMP);
			pr_info("PTP Clock: Using GPIO %d at %lld Hz\n",
				ptp.s.ext_clk_in,
				(NSEC_PER_SEC << 32) / clock_comp);
		}

		/* Enable the clock if it wasn't done already */
		if (!ptp.s.ptp_en) {
			ptp.s.ptp_en = 1;
			cvmx_write_csr(CVMX_MIO_PTP_CLOCK_CFG, ptp.u64);
		}
		have_hw_timestamps = 1;
		/* Only the first two interfaces support hardware timestamps */
		if (priv->port >= 32)
			have_hw_timestamps = 0;
	}

	/* Require hardware if ALLOW_TIMESTAMPS_WITHOUT_HARDWARE=0 */
	if (!ALLOW_TIMESTAMPS_WITHOUT_HARDWARE && !have_hw_timestamps)
		return -EINVAL;

	switch (config.tx_type) {
		case HWTSTAMP_TX_OFF:
			priv->flags &= ~(OCTEON_ETHERNET_FLAG_TX_TIMESTAMP_SW |
					 OCTEON_ETHERNET_FLAG_TX_TIMESTAMP_HW);
			break;
		case HWTSTAMP_TX_ON:
			priv->flags |= (have_hw_timestamps) ?
				OCTEON_ETHERNET_FLAG_TX_TIMESTAMP_HW :
				OCTEON_ETHERNET_FLAG_TX_TIMESTAMP_SW;
			break;
		default:
			return -ERANGE;
	}

	switch (config.rx_filter) {
		case HWTSTAMP_FILTER_NONE:
			priv->flags &= ~(OCTEON_ETHERNET_FLAG_RX_TIMESTAMP_HW |
					 OCTEON_ETHERNET_FLAG_RX_TIMESTAMP_SW);
			if (have_hw_timestamps) {
				int interface = INTERFACE(priv->port);
				int index = INDEX(priv->port);
				union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl;
				union cvmx_pip_prt_cfgx pip_prt_cfgx;

				gmxx_rxx_frm_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface));
				gmxx_rxx_frm_ctl.s.ptp_mode = 0;
				cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface), gmxx_rxx_frm_ctl.u64);

				pip_prt_cfgx.u64 = cvmx_read_csr(CVMX_PIP_PRT_CFGX(priv->port));
				pip_prt_cfgx.s.skip = 0;
				cvmx_write_csr(CVMX_PIP_PRT_CFGX(priv->port), pip_prt_cfgx.u64);
			}
			break;
		case HWTSTAMP_FILTER_ALL:
		case HWTSTAMP_FILTER_SOME:
		case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
		case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
		case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
		case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
		case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
		case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
		case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
		case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
		case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
		case HWTSTAMP_FILTER_PTP_V2_EVENT:
		case HWTSTAMP_FILTER_PTP_V2_SYNC:
		case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
			priv->flags |= (have_hw_timestamps) ?
				OCTEON_ETHERNET_FLAG_RX_TIMESTAMP_HW :
				OCTEON_ETHERNET_FLAG_RX_TIMESTAMP_SW;
			config.rx_filter = HWTSTAMP_FILTER_ALL;
			if (have_hw_timestamps) {
				int interface = INTERFACE(priv->port);
				int index = INDEX(priv->port);
				union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl;
				union cvmx_pip_prt_cfgx pip_prt_cfgx;

				gmxx_rxx_frm_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface));
				gmxx_rxx_frm_ctl.s.ptp_mode = 1;
				cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface), gmxx_rxx_frm_ctl.u64);

				pip_prt_cfgx.u64 = cvmx_read_csr(CVMX_PIP_PRT_CFGX(priv->port));
				pip_prt_cfgx.s.skip = 8;
				cvmx_write_csr(CVMX_PIP_PRT_CFGX(priv->port), pip_prt_cfgx.u64);
			}
			break;
		default:
			return -ERANGE;
	}

	if (copy_to_user(rq->ifr_data, &config, sizeof(config)))
		return -EFAULT;

	return 0;
}