/** * 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; }
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; }
/** * 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; }
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; };
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); }
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; }