/** * \brief KSZ8851SNL initialization function. * * \return 0 on success, 1 on communication error. */ uint32_t ksz8851snl_init(void) { uint32_t count = 0; uint16_t dev_id = 0; /* Configure the SPI peripheral. */ spi_enable_clock(KSZ8851SNL_SPI); spi_disable(KSZ8851SNL_SPI); spi_reset(KSZ8851SNL_SPI); spi_set_master_mode(KSZ8851SNL_SPI); spi_disable_mode_fault_detect(KSZ8851SNL_SPI); spi_set_peripheral_chip_select_value(KSZ8851SNL_SPI, ~(uint32_t)(1 << KSZ8851SNL_CS_PIN)); spi_set_clock_polarity(KSZ8851SNL_SPI, KSZ8851SNL_CS_PIN, SPI_CLK_POLARITY); spi_set_clock_phase(KSZ8851SNL_SPI, KSZ8851SNL_CS_PIN, SPI_CLK_PHASE); spi_set_bits_per_transfer(KSZ8851SNL_SPI, KSZ8851SNL_CS_PIN, SPI_CSR_BITS_8_BIT); spi_set_baudrate_div(KSZ8851SNL_SPI, KSZ8851SNL_CS_PIN, (sysclk_get_cpu_hz() / KSZ8851SNL_CLOCK_SPEED)); spi_set_transfer_delay(KSZ8851SNL_SPI, KSZ8851SNL_CS_PIN, CONFIG_SPI_MASTER_DELAY_BS, CONFIG_SPI_MASTER_DELAY_BCT); spi_enable(KSZ8851SNL_SPI); /* Get pointer to UART PDC register base. */ g_p_spi_pdc = spi_get_pdc_base(KSZ8851SNL_SPI); pdc_enable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN); /* Control RSTN and CSN pin from the driver. */ gpio_configure_pin(KSZ8851SNL_CSN_GPIO, KSZ8851SNL_CSN_FLAGS); gpio_set_pin_high(KSZ8851SNL_CSN_GPIO); gpio_configure_pin(KSZ8851SNL_RSTN_GPIO, KSZ8851SNL_RSTN_FLAGS); /* Reset the Micrel in a proper state. */ do { /* Perform hardware reset with respect to the reset timing from the datasheet. */ gpio_set_pin_low(KSZ8851SNL_RSTN_GPIO); delay_ms(100); gpio_set_pin_high(KSZ8851SNL_RSTN_GPIO); delay_ms(100); /* Init step1: read chip ID. */ dev_id = ksz8851_reg_read(REG_CHIP_ID); if (++count > 10) return 1; } while ((dev_id & 0xFFF0) != CHIP_ID_8851_16); /* Init step2-4: write QMU MAC address (low, middle then high). */ ksz8851_reg_write(REG_MAC_ADDR_0, (ETHERNET_CONF_ETHADDR4 << 8) | ETHERNET_CONF_ETHADDR5); ksz8851_reg_write(REG_MAC_ADDR_2, (ETHERNET_CONF_ETHADDR2 << 8) | ETHERNET_CONF_ETHADDR3); ksz8851_reg_write(REG_MAC_ADDR_4, (ETHERNET_CONF_ETHADDR0 << 8) | ETHERNET_CONF_ETHADDR1); /* Init step5: enable QMU Transmit Frame Data Pointer Auto Increment. */ ksz8851_reg_write(REG_TX_ADDR_PTR, ADDR_PTR_AUTO_INC); /* Init step6: configure QMU transmit control register. */ ksz8851_reg_write(REG_TX_CTRL, TX_CTRL_ICMP_CHECKSUM | TX_CTRL_UDP_CHECKSUM | TX_CTRL_TCP_CHECKSUM | TX_CTRL_IP_CHECKSUM | TX_CTRL_FLOW_ENABLE | TX_CTRL_PAD_ENABLE | TX_CTRL_CRC_ENABLE ); /* Init step7: enable QMU Receive Frame Data Pointer Auto Increment. */ ksz8851_reg_write(REG_RX_ADDR_PTR, ADDR_PTR_AUTO_INC); /* Init step8: configure QMU Receive Frame Threshold for one frame. */ ksz8851_reg_write(REG_RX_FRAME_CNT_THRES, 1); /* Init step9: configure QMU receive control register1. */ ksz8851_reg_write(REG_RX_CTRL1, RX_CTRL_UDP_CHECKSUM | RX_CTRL_TCP_CHECKSUM | RX_CTRL_IP_CHECKSUM | RX_CTRL_MAC_FILTER | RX_CTRL_FLOW_ENABLE | RX_CTRL_BROADCAST | RX_CTRL_ALL_MULTICAST| RX_CTRL_UNICAST); /* Init step10: configure QMU receive control register2. */ ksz8851_reg_write(REG_RX_CTRL2, RX_CTRL_IPV6_UDP_NOCHECKSUM | RX_CTRL_UDP_LITE_CHECKSUM | RX_CTRL_ICMP_CHECKSUM | RX_CTRL_BURST_LEN_FRAME); /* Init step11: configure QMU receive queue: trigger INT and auto-dequeue frame. */ ksz8851_reg_write(REG_RXQ_CMD, RXQ_CMD_CNTL); /* Init step12: adjust SPI data output delay. */ ksz8851_reg_write(REG_BUS_CLOCK_CTRL, BUS_CLOCK_166 | BUS_CLOCK_DIVIDEDBY_1); /* Init step13: restart auto-negotiation. */ ksz8851_reg_setbits(REG_PORT_CTRL, PORT_AUTO_NEG_RESTART); /* Init step13.1: force link in half duplex if auto-negotiation failed. */ if ((ksz8851_reg_read(REG_PORT_CTRL) & PORT_AUTO_NEG_RESTART) != PORT_AUTO_NEG_RESTART) { ksz8851_reg_clrbits(REG_PORT_CTRL, PORT_FORCE_FULL_DUPLEX); } /* Init step14: clear interrupt status. */ ksz8851_reg_write(REG_INT_STATUS, 0xFFFF); /* Init step15: set interrupt mask. */ ksz8851_reg_write(REG_INT_MASK, INT_RX); /* Init step16: enable QMU Transmit. */ ksz8851_reg_setbits(REG_TX_CTRL, TX_CTRL_ENABLE); /* Init step17: enable QMU Receive. */ ksz8851_reg_setbits(REG_RX_CTRL1, RX_CTRL_ENABLE); return 0; }
/** * \brief Initialize the PHY controller * * Call this function to initialize the hardware interface and the PHY * controller. When initialization is done the PHY is turned on and ready * to receive data. */ uint32_t ksz8851snl_init(void) { uint32_t count = 0; uint16_t dev_id = 0; /* Initialize delay routine. */ delay_init(); /* Initialize the SPI interface. */ ksz8851snl_interface_init(); /* Reset the Micrel in a proper state. */ do { ksz8851snl_hard_reset(); /* Init step1: read chip ID. */ dev_id = ksz8851_reg_read(REG_CHIP_ID); if (++count > 10) return 1; } while ((dev_id & 0xFFF0) != CHIP_ID_8851_16); /* Init step2-4: write QMU MAC address (low, middle then high). */ ksz8851_reg_write(REG_MAC_ADDR_0, (ETHERNET_CONF_ETHADDR4 << 8) | ETHERNET_CONF_ETHADDR5); ksz8851_reg_write(REG_MAC_ADDR_2, (ETHERNET_CONF_ETHADDR2 << 8) | ETHERNET_CONF_ETHADDR3); ksz8851_reg_write(REG_MAC_ADDR_4, (ETHERNET_CONF_ETHADDR0 << 8) | ETHERNET_CONF_ETHADDR1); /* Init step5: enable QMU Transmit Frame Data Pointer Auto Increment. */ ksz8851_reg_write(REG_TX_ADDR_PTR, ADDR_PTR_AUTO_INC); /* Init step6: configure QMU transmit control register. */ ksz8851_reg_write(REG_TX_CTRL, TX_CTRL_ICMP_CHECKSUM | TX_CTRL_UDP_CHECKSUM | TX_CTRL_TCP_CHECKSUM | TX_CTRL_IP_CHECKSUM | TX_CTRL_FLOW_ENABLE | TX_CTRL_PAD_ENABLE | TX_CTRL_CRC_ENABLE ); /* Init step7: enable QMU Receive Frame Data Pointer Auto Increment. */ ksz8851_reg_write(REG_RX_ADDR_PTR, ADDR_PTR_AUTO_INC); /* Init step8: configure QMU Receive Frame Threshold for one frame. */ ksz8851_reg_write(REG_RX_FRAME_CNT_THRES, 1); /* Init step9: configure QMU receive control register1. */ ksz8851_reg_write(REG_RX_CTRL1, RX_CTRL_UDP_CHECKSUM | RX_CTRL_TCP_CHECKSUM | RX_CTRL_IP_CHECKSUM | RX_CTRL_MAC_FILTER | RX_CTRL_FLOW_ENABLE | RX_CTRL_BROADCAST | RX_CTRL_ALL_MULTICAST| RX_CTRL_UNICAST); /* Init step10: configure QMU receive control register2. */ ksz8851_reg_write(REG_RX_CTRL2, RX_CTRL_IPV6_UDP_NOCHECKSUM | RX_CTRL_UDP_LITE_CHECKSUM | RX_CTRL_ICMP_CHECKSUM | RX_CTRL_BURST_LEN_FRAME); /* Init step11: configure QMU receive queue: trigger INT and auto-dequeue frame. */ ksz8851_reg_write(REG_RXQ_CMD, RXQ_CMD_CNTL | RXQ_TWOBYTE_OFFSET); /* Init step12: adjust SPI data output delay. */ ksz8851_reg_write(REG_BUS_CLOCK_CTRL, BUS_CLOCK_166 | BUS_CLOCK_DIVIDEDBY_1); /* Init step13: restart auto-negotiation. */ ksz8851_reg_setbits(REG_PORT_CTRL, PORT_AUTO_NEG_RESTART); /* Init step13.1: force link in half duplex if auto-negotiation failed. */ if ((ksz8851_reg_read(REG_PORT_CTRL) & PORT_AUTO_NEG_RESTART) != PORT_AUTO_NEG_RESTART) { ksz8851_reg_clrbits(REG_PORT_CTRL, PORT_FORCE_FULL_DUPLEX); } /* Init step14: clear interrupt status. */ ksz8851_reg_write(REG_INT_STATUS, 0xFFFF); /* Init step15: set interrupt mask. */ ksz8851_reg_write(REG_INT_MASK, INT_RX); /* Init step16: enable QMU Transmit. */ ksz8851_reg_setbits(REG_TX_CTRL, TX_CTRL_ENABLE); /* Init step17: enable QMU Receive. */ ksz8851_reg_setbits(REG_RX_CTRL1, RX_CTRL_ENABLE); return 0; }
void ksz8851snl_set_registers(void) { /* Init step2-4: write QMU MAC address (low, middle then high). */ ksz8851_reg_write(REG_MAC_ADDR_0, (ETHERNET_CONF_ETHADDR4 << 8) | ETHERNET_CONF_ETHADDR5); ksz8851_reg_write(REG_MAC_ADDR_2, (ETHERNET_CONF_ETHADDR2 << 8) | ETHERNET_CONF_ETHADDR3); ksz8851_reg_write(REG_MAC_ADDR_4, (ETHERNET_CONF_ETHADDR0 << 8) | ETHERNET_CONF_ETHADDR1); /* Init step5: enable QMU Transmit Frame Data Pointer Auto Increment. */ ksz8851_reg_write(REG_TX_ADDR_PTR, ADDR_PTR_AUTO_INC); /* Init step6: configure QMU transmit control register. */ ksz8851_reg_write(REG_TX_CTRL, TX_CTRL_ICMP_CHECKSUM | TX_CTRL_UDP_CHECKSUM | TX_CTRL_TCP_CHECKSUM | TX_CTRL_IP_CHECKSUM | TX_CTRL_FLOW_ENABLE | TX_CTRL_PAD_ENABLE | TX_CTRL_CRC_ENABLE ); /* Init step7: enable QMU Receive Frame Data Pointer Auto Increment. */ ksz8851_reg_write(REG_RX_ADDR_PTR, ADDR_PTR_AUTO_INC); /* Init step8: configure QMU Receive Frame Threshold for one frame. */ ksz8851_reg_write(REG_RX_FRAME_CNT_THRES, 1); /* Init step9: configure QMU receive control register1. */ ksz8851_reg_write(REG_RX_CTRL1, RX_CTRL_UDP_CHECKSUM | RX_CTRL_TCP_CHECKSUM | RX_CTRL_IP_CHECKSUM | RX_CTRL_MAC_FILTER | RX_CTRL_FLOW_ENABLE | RX_CTRL_BROADCAST | RX_CTRL_ALL_MULTICAST| RX_CTRL_UNICAST); // ksz8851_reg_write(REG_RX_CTRL1, // RX_CTRL_UDP_CHECKSUM | // RX_CTRL_TCP_CHECKSUM | // RX_CTRL_IP_CHECKSUM | // RX_CTRL_FLOW_ENABLE | // RX_CTRL_PROMISCUOUS); ksz8851_reg_write(REG_RX_CTRL2, RX_CTRL_IPV6_UDP_NOCHECKSUM | RX_CTRL_UDP_LITE_CHECKSUM | RX_CTRL_ICMP_CHECKSUM | RX_CTRL_BURST_LEN_FRAME); //#define RXQ_TWOBYTE_OFFSET (0x0200) /* Enable adding 2-byte before frame header for IP aligned with DWORD */ #warning Remember to try the above option to get a 2-byte offset /* Init step11: configure QMU receive queue: trigger INT and auto-dequeue frame. */ ksz8851_reg_write( REG_RXQ_CMD, RXQ_CMD_CNTL | RXQ_TWOBYTE_OFFSET ); /* Init step12: adjust SPI data output delay. */ ksz8851_reg_write(REG_BUS_CLOCK_CTRL, BUS_CLOCK_166 | BUS_CLOCK_DIVIDEDBY_1); /* Init step13: restart auto-negotiation. */ ksz8851_reg_setbits(REG_PORT_CTRL, PORT_AUTO_NEG_RESTART); /* Init step13.1: force link in half duplex if auto-negotiation failed. */ if ((ksz8851_reg_read(REG_PORT_CTRL) & PORT_AUTO_NEG_RESTART) != PORT_AUTO_NEG_RESTART) { ksz8851_reg_clrbits(REG_PORT_CTRL, PORT_FORCE_FULL_DUPLEX); } /* Init step14: clear interrupt status. */ ksz8851_reg_write(REG_INT_STATUS, 0xFFFF); /* Init step15: set interrupt mask. */ ksz8851_reg_write(REG_INT_MASK, INT_RX); /* Init step16: enable QMU Transmit. */ ksz8851_reg_setbits(REG_TX_CTRL, TX_CTRL_ENABLE); /* Init step17: enable QMU Receive. */ ksz8851_reg_setbits(REG_RX_CTRL1, RX_CTRL_ENABLE); }