18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 38c2ecf20Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 48c2ecf20Sopenharmony_ci * for more details. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2004-2017 Cavium, Inc. 78c2ecf20Sopenharmony_ci * Copyright (C) 2008 Wind River Systems 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 118c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 128c2ecf20Sopenharmony_ci#include <linux/of_fdt.h> 138c2ecf20Sopenharmony_ci#include <linux/libfdt.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <asm/octeon/octeon.h> 168c2ecf20Sopenharmony_ci#include <asm/octeon/cvmx-helper-board.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#ifdef CONFIG_USB 198c2ecf20Sopenharmony_ci#include <linux/usb/ehci_def.h> 208c2ecf20Sopenharmony_ci#include <linux/usb/ehci_pdriver.h> 218c2ecf20Sopenharmony_ci#include <linux/usb/ohci_pdriver.h> 228c2ecf20Sopenharmony_ci#include <asm/octeon/cvmx-uctlx-defs.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define CVMX_UAHCX_EHCI_USBCMD (CVMX_ADD_IO_SEG(0x00016F0000000010ull)) 258c2ecf20Sopenharmony_ci#define CVMX_UAHCX_OHCI_USBCMD (CVMX_ADD_IO_SEG(0x00016F0000000408ull)) 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(octeon2_usb_clocks_mutex); 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic int octeon2_usb_clock_start_cnt; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic int __init octeon2_usb_reset(void) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci union cvmx_uctlx_clk_rst_ctl clk_rst_ctl; 348c2ecf20Sopenharmony_ci u32 ucmd; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci if (!OCTEON_IS_OCTEON2()) 378c2ecf20Sopenharmony_ci return 0; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0)); 408c2ecf20Sopenharmony_ci if (clk_rst_ctl.s.hrst) { 418c2ecf20Sopenharmony_ci ucmd = cvmx_read64_uint32(CVMX_UAHCX_EHCI_USBCMD); 428c2ecf20Sopenharmony_ci ucmd &= ~CMD_RUN; 438c2ecf20Sopenharmony_ci cvmx_write64_uint32(CVMX_UAHCX_EHCI_USBCMD, ucmd); 448c2ecf20Sopenharmony_ci mdelay(2); 458c2ecf20Sopenharmony_ci ucmd |= CMD_RESET; 468c2ecf20Sopenharmony_ci cvmx_write64_uint32(CVMX_UAHCX_EHCI_USBCMD, ucmd); 478c2ecf20Sopenharmony_ci ucmd = cvmx_read64_uint32(CVMX_UAHCX_OHCI_USBCMD); 488c2ecf20Sopenharmony_ci ucmd |= CMD_RUN; 498c2ecf20Sopenharmony_ci cvmx_write64_uint32(CVMX_UAHCX_OHCI_USBCMD, ucmd); 508c2ecf20Sopenharmony_ci } 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci return 0; 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ciarch_initcall(octeon2_usb_reset); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic void octeon2_usb_clocks_start(struct device *dev) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci u64 div; 598c2ecf20Sopenharmony_ci union cvmx_uctlx_if_ena if_ena; 608c2ecf20Sopenharmony_ci union cvmx_uctlx_clk_rst_ctl clk_rst_ctl; 618c2ecf20Sopenharmony_ci union cvmx_uctlx_uphy_portx_ctl_status port_ctl_status; 628c2ecf20Sopenharmony_ci int i; 638c2ecf20Sopenharmony_ci unsigned long io_clk_64_to_ns; 648c2ecf20Sopenharmony_ci u32 clock_rate = 12000000; 658c2ecf20Sopenharmony_ci bool is_crystal_clock = false; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci mutex_lock(&octeon2_usb_clocks_mutex); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci octeon2_usb_clock_start_cnt++; 718c2ecf20Sopenharmony_ci if (octeon2_usb_clock_start_cnt != 1) 728c2ecf20Sopenharmony_ci goto exit; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci io_clk_64_to_ns = 64000000000ull / octeon_get_io_clock_rate(); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci if (dev->of_node) { 778c2ecf20Sopenharmony_ci struct device_node *uctl_node; 788c2ecf20Sopenharmony_ci const char *clock_type; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci uctl_node = of_get_parent(dev->of_node); 818c2ecf20Sopenharmony_ci if (!uctl_node) { 828c2ecf20Sopenharmony_ci dev_err(dev, "No UCTL device node\n"); 838c2ecf20Sopenharmony_ci goto exit; 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci i = of_property_read_u32(uctl_node, 868c2ecf20Sopenharmony_ci "refclk-frequency", &clock_rate); 878c2ecf20Sopenharmony_ci if (i) { 888c2ecf20Sopenharmony_ci dev_err(dev, "No UCTL \"refclk-frequency\"\n"); 898c2ecf20Sopenharmony_ci of_node_put(uctl_node); 908c2ecf20Sopenharmony_ci goto exit; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci i = of_property_read_string(uctl_node, 938c2ecf20Sopenharmony_ci "refclk-type", &clock_type); 948c2ecf20Sopenharmony_ci of_node_put(uctl_node); 958c2ecf20Sopenharmony_ci if (!i && strcmp("crystal", clock_type) == 0) 968c2ecf20Sopenharmony_ci is_crystal_clock = true; 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci /* 1008c2ecf20Sopenharmony_ci * Step 1: Wait for voltages stable. That surely happened 1018c2ecf20Sopenharmony_ci * before starting the kernel. 1028c2ecf20Sopenharmony_ci * 1038c2ecf20Sopenharmony_ci * Step 2: Enable SCLK of UCTL by writing UCTL0_IF_ENA[EN] = 1 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_ci if_ena.u64 = 0; 1068c2ecf20Sopenharmony_ci if_ena.s.en = 1; 1078c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_UCTLX_IF_ENA(0), if_ena.u64); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci for (i = 0; i <= 1; i++) { 1108c2ecf20Sopenharmony_ci port_ctl_status.u64 = 1118c2ecf20Sopenharmony_ci cvmx_read_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0)); 1128c2ecf20Sopenharmony_ci /* Set txvreftune to 15 to obtain compliant 'eye' diagram. */ 1138c2ecf20Sopenharmony_ci port_ctl_status.s.txvreftune = 15; 1148c2ecf20Sopenharmony_ci port_ctl_status.s.txrisetune = 1; 1158c2ecf20Sopenharmony_ci port_ctl_status.s.txpreemphasistune = 1; 1168c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0), 1178c2ecf20Sopenharmony_ci port_ctl_status.u64); 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci /* Step 3: Configure the reference clock, PHY, and HCLK */ 1218c2ecf20Sopenharmony_ci clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0)); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci /* 1248c2ecf20Sopenharmony_ci * If the UCTL looks like it has already been started, skip 1258c2ecf20Sopenharmony_ci * the initialization, otherwise bus errors are obtained. 1268c2ecf20Sopenharmony_ci */ 1278c2ecf20Sopenharmony_ci if (clk_rst_ctl.s.hrst) 1288c2ecf20Sopenharmony_ci goto end_clock; 1298c2ecf20Sopenharmony_ci /* 3a */ 1308c2ecf20Sopenharmony_ci clk_rst_ctl.s.p_por = 1; 1318c2ecf20Sopenharmony_ci clk_rst_ctl.s.hrst = 0; 1328c2ecf20Sopenharmony_ci clk_rst_ctl.s.p_prst = 0; 1338c2ecf20Sopenharmony_ci clk_rst_ctl.s.h_clkdiv_rst = 0; 1348c2ecf20Sopenharmony_ci clk_rst_ctl.s.o_clkdiv_rst = 0; 1358c2ecf20Sopenharmony_ci clk_rst_ctl.s.h_clkdiv_en = 0; 1368c2ecf20Sopenharmony_ci clk_rst_ctl.s.o_clkdiv_en = 0; 1378c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci /* 3b */ 1408c2ecf20Sopenharmony_ci clk_rst_ctl.s.p_refclk_sel = is_crystal_clock ? 0 : 1; 1418c2ecf20Sopenharmony_ci switch (clock_rate) { 1428c2ecf20Sopenharmony_ci default: 1438c2ecf20Sopenharmony_ci pr_err("Invalid UCTL clock rate of %u, using 12000000 instead\n", 1448c2ecf20Sopenharmony_ci clock_rate); 1458c2ecf20Sopenharmony_ci fallthrough; 1468c2ecf20Sopenharmony_ci case 12000000: 1478c2ecf20Sopenharmony_ci clk_rst_ctl.s.p_refclk_div = 0; 1488c2ecf20Sopenharmony_ci break; 1498c2ecf20Sopenharmony_ci case 24000000: 1508c2ecf20Sopenharmony_ci clk_rst_ctl.s.p_refclk_div = 1; 1518c2ecf20Sopenharmony_ci break; 1528c2ecf20Sopenharmony_ci case 48000000: 1538c2ecf20Sopenharmony_ci clk_rst_ctl.s.p_refclk_div = 2; 1548c2ecf20Sopenharmony_ci break; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci /* 3c */ 1598c2ecf20Sopenharmony_ci div = octeon_get_io_clock_rate() / 130000000ull; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci switch (div) { 1628c2ecf20Sopenharmony_ci case 0: 1638c2ecf20Sopenharmony_ci div = 1; 1648c2ecf20Sopenharmony_ci break; 1658c2ecf20Sopenharmony_ci case 1: 1668c2ecf20Sopenharmony_ci case 2: 1678c2ecf20Sopenharmony_ci case 3: 1688c2ecf20Sopenharmony_ci case 4: 1698c2ecf20Sopenharmony_ci break; 1708c2ecf20Sopenharmony_ci case 5: 1718c2ecf20Sopenharmony_ci div = 4; 1728c2ecf20Sopenharmony_ci break; 1738c2ecf20Sopenharmony_ci case 6: 1748c2ecf20Sopenharmony_ci case 7: 1758c2ecf20Sopenharmony_ci div = 6; 1768c2ecf20Sopenharmony_ci break; 1778c2ecf20Sopenharmony_ci case 8: 1788c2ecf20Sopenharmony_ci case 9: 1798c2ecf20Sopenharmony_ci case 10: 1808c2ecf20Sopenharmony_ci case 11: 1818c2ecf20Sopenharmony_ci div = 8; 1828c2ecf20Sopenharmony_ci break; 1838c2ecf20Sopenharmony_ci default: 1848c2ecf20Sopenharmony_ci div = 12; 1858c2ecf20Sopenharmony_ci break; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci clk_rst_ctl.s.h_div = div; 1888c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 1898c2ecf20Sopenharmony_ci /* Read it back, */ 1908c2ecf20Sopenharmony_ci clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0)); 1918c2ecf20Sopenharmony_ci clk_rst_ctl.s.h_clkdiv_en = 1; 1928c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 1938c2ecf20Sopenharmony_ci /* 3d */ 1948c2ecf20Sopenharmony_ci clk_rst_ctl.s.h_clkdiv_rst = 1; 1958c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci /* 3e: delay 64 io clocks */ 1988c2ecf20Sopenharmony_ci ndelay(io_clk_64_to_ns); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci /* 2018c2ecf20Sopenharmony_ci * Step 4: Program the power-on reset field in the UCTL 2028c2ecf20Sopenharmony_ci * clock-reset-control register. 2038c2ecf20Sopenharmony_ci */ 2048c2ecf20Sopenharmony_ci clk_rst_ctl.s.p_por = 0; 2058c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci /* Step 5: Wait 3 ms for the PHY clock to start. */ 2088c2ecf20Sopenharmony_ci mdelay(3); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci /* Steps 6..9 for ATE only, are skipped. */ 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci /* Step 10: Configure the OHCI_CLK48 and OHCI_CLK12 clocks. */ 2138c2ecf20Sopenharmony_ci /* 10a */ 2148c2ecf20Sopenharmony_ci clk_rst_ctl.s.o_clkdiv_rst = 1; 2158c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci /* 10b */ 2188c2ecf20Sopenharmony_ci clk_rst_ctl.s.o_clkdiv_en = 1; 2198c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci /* 10c */ 2228c2ecf20Sopenharmony_ci ndelay(io_clk_64_to_ns); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci /* 2258c2ecf20Sopenharmony_ci * Step 11: Program the PHY reset field: 2268c2ecf20Sopenharmony_ci * UCTL0_CLK_RST_CTL[P_PRST] = 1 2278c2ecf20Sopenharmony_ci */ 2288c2ecf20Sopenharmony_ci clk_rst_ctl.s.p_prst = 1; 2298c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci /* Step 11b */ 2328c2ecf20Sopenharmony_ci udelay(1); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci /* Step 11c */ 2358c2ecf20Sopenharmony_ci clk_rst_ctl.s.p_prst = 0; 2368c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci /* Step 11d */ 2398c2ecf20Sopenharmony_ci mdelay(1); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci /* Step 11e */ 2428c2ecf20Sopenharmony_ci clk_rst_ctl.s.p_prst = 1; 2438c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci /* Step 12: Wait 1 uS. */ 2468c2ecf20Sopenharmony_ci udelay(1); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci /* Step 13: Program the HRESET_N field: UCTL0_CLK_RST_CTL[HRST] = 1 */ 2498c2ecf20Sopenharmony_ci clk_rst_ctl.s.hrst = 1; 2508c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ciend_clock: 2538c2ecf20Sopenharmony_ci /* Set uSOF cycle period to 60,000 bits. */ 2548c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_UCTLX_EHCI_FLA(0), 0x20ull); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ciexit: 2578c2ecf20Sopenharmony_ci mutex_unlock(&octeon2_usb_clocks_mutex); 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic void octeon2_usb_clocks_stop(void) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci mutex_lock(&octeon2_usb_clocks_mutex); 2638c2ecf20Sopenharmony_ci octeon2_usb_clock_start_cnt--; 2648c2ecf20Sopenharmony_ci mutex_unlock(&octeon2_usb_clocks_mutex); 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic int octeon_ehci_power_on(struct platform_device *pdev) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci octeon2_usb_clocks_start(&pdev->dev); 2708c2ecf20Sopenharmony_ci return 0; 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic void octeon_ehci_power_off(struct platform_device *pdev) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci octeon2_usb_clocks_stop(); 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic struct usb_ehci_pdata octeon_ehci_pdata = { 2798c2ecf20Sopenharmony_ci /* Octeon EHCI matches CPU endianness. */ 2808c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 2818c2ecf20Sopenharmony_ci .big_endian_mmio = 1, 2828c2ecf20Sopenharmony_ci#endif 2838c2ecf20Sopenharmony_ci /* 2848c2ecf20Sopenharmony_ci * We can DMA from anywhere. But the descriptors must be in 2858c2ecf20Sopenharmony_ci * the lower 4GB. 2868c2ecf20Sopenharmony_ci */ 2878c2ecf20Sopenharmony_ci .dma_mask_64 = 0, 2888c2ecf20Sopenharmony_ci .power_on = octeon_ehci_power_on, 2898c2ecf20Sopenharmony_ci .power_off = octeon_ehci_power_off, 2908c2ecf20Sopenharmony_ci}; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic void __init octeon_ehci_hw_start(struct device *dev) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci union cvmx_uctlx_ehci_ctl ehci_ctl; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci octeon2_usb_clocks_start(dev); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci ehci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_EHCI_CTL(0)); 2998c2ecf20Sopenharmony_ci /* Use 64-bit addressing. */ 3008c2ecf20Sopenharmony_ci ehci_ctl.s.ehci_64b_addr_en = 1; 3018c2ecf20Sopenharmony_ci ehci_ctl.s.l2c_addr_msb = 0; 3028c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 3038c2ecf20Sopenharmony_ci ehci_ctl.s.l2c_buff_emod = 1; /* Byte swapped. */ 3048c2ecf20Sopenharmony_ci ehci_ctl.s.l2c_desc_emod = 1; /* Byte swapped. */ 3058c2ecf20Sopenharmony_ci#else 3068c2ecf20Sopenharmony_ci ehci_ctl.s.l2c_buff_emod = 0; /* not swapped. */ 3078c2ecf20Sopenharmony_ci ehci_ctl.s.l2c_desc_emod = 0; /* not swapped. */ 3088c2ecf20Sopenharmony_ci ehci_ctl.s.inv_reg_a2 = 1; 3098c2ecf20Sopenharmony_ci#endif 3108c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_UCTLX_EHCI_CTL(0), ehci_ctl.u64); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci octeon2_usb_clocks_stop(); 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_cistatic int __init octeon_ehci_device_init(void) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci struct platform_device *pd; 3188c2ecf20Sopenharmony_ci struct device_node *ehci_node; 3198c2ecf20Sopenharmony_ci int ret = 0; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci ehci_node = of_find_node_by_name(NULL, "ehci"); 3228c2ecf20Sopenharmony_ci if (!ehci_node) 3238c2ecf20Sopenharmony_ci return 0; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci pd = of_find_device_by_node(ehci_node); 3268c2ecf20Sopenharmony_ci of_node_put(ehci_node); 3278c2ecf20Sopenharmony_ci if (!pd) 3288c2ecf20Sopenharmony_ci return 0; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci pd->dev.platform_data = &octeon_ehci_pdata; 3318c2ecf20Sopenharmony_ci octeon_ehci_hw_start(&pd->dev); 3328c2ecf20Sopenharmony_ci put_device(&pd->dev); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci return ret; 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_cidevice_initcall(octeon_ehci_device_init); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic int octeon_ohci_power_on(struct platform_device *pdev) 3398c2ecf20Sopenharmony_ci{ 3408c2ecf20Sopenharmony_ci octeon2_usb_clocks_start(&pdev->dev); 3418c2ecf20Sopenharmony_ci return 0; 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic void octeon_ohci_power_off(struct platform_device *pdev) 3458c2ecf20Sopenharmony_ci{ 3468c2ecf20Sopenharmony_ci octeon2_usb_clocks_stop(); 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic struct usb_ohci_pdata octeon_ohci_pdata = { 3508c2ecf20Sopenharmony_ci /* Octeon OHCI matches CPU endianness. */ 3518c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 3528c2ecf20Sopenharmony_ci .big_endian_mmio = 1, 3538c2ecf20Sopenharmony_ci#endif 3548c2ecf20Sopenharmony_ci .power_on = octeon_ohci_power_on, 3558c2ecf20Sopenharmony_ci .power_off = octeon_ohci_power_off, 3568c2ecf20Sopenharmony_ci}; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_cistatic void __init octeon_ohci_hw_start(struct device *dev) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci union cvmx_uctlx_ohci_ctl ohci_ctl; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci octeon2_usb_clocks_start(dev); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci ohci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_OHCI_CTL(0)); 3658c2ecf20Sopenharmony_ci ohci_ctl.s.l2c_addr_msb = 0; 3668c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 3678c2ecf20Sopenharmony_ci ohci_ctl.s.l2c_buff_emod = 1; /* Byte swapped. */ 3688c2ecf20Sopenharmony_ci ohci_ctl.s.l2c_desc_emod = 1; /* Byte swapped. */ 3698c2ecf20Sopenharmony_ci#else 3708c2ecf20Sopenharmony_ci ohci_ctl.s.l2c_buff_emod = 0; /* not swapped. */ 3718c2ecf20Sopenharmony_ci ohci_ctl.s.l2c_desc_emod = 0; /* not swapped. */ 3728c2ecf20Sopenharmony_ci ohci_ctl.s.inv_reg_a2 = 1; 3738c2ecf20Sopenharmony_ci#endif 3748c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_UCTLX_OHCI_CTL(0), ohci_ctl.u64); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci octeon2_usb_clocks_stop(); 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cistatic int __init octeon_ohci_device_init(void) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci struct platform_device *pd; 3828c2ecf20Sopenharmony_ci struct device_node *ohci_node; 3838c2ecf20Sopenharmony_ci int ret = 0; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci ohci_node = of_find_node_by_name(NULL, "ohci"); 3868c2ecf20Sopenharmony_ci if (!ohci_node) 3878c2ecf20Sopenharmony_ci return 0; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci pd = of_find_device_by_node(ohci_node); 3908c2ecf20Sopenharmony_ci of_node_put(ohci_node); 3918c2ecf20Sopenharmony_ci if (!pd) 3928c2ecf20Sopenharmony_ci return 0; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci pd->dev.platform_data = &octeon_ohci_pdata; 3958c2ecf20Sopenharmony_ci octeon_ohci_hw_start(&pd->dev); 3968c2ecf20Sopenharmony_ci put_device(&pd->dev); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci return ret; 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_cidevice_initcall(octeon_ohci_device_init); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci#endif /* CONFIG_USB */ 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci/* Octeon Random Number Generator. */ 4058c2ecf20Sopenharmony_cistatic int __init octeon_rng_device_init(void) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci struct platform_device *pd; 4088c2ecf20Sopenharmony_ci int ret = 0; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci struct resource rng_resources[] = { 4118c2ecf20Sopenharmony_ci { 4128c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM, 4138c2ecf20Sopenharmony_ci .start = XKPHYS_TO_PHYS(CVMX_RNM_CTL_STATUS), 4148c2ecf20Sopenharmony_ci .end = XKPHYS_TO_PHYS(CVMX_RNM_CTL_STATUS) + 0xf 4158c2ecf20Sopenharmony_ci }, { 4168c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM, 4178c2ecf20Sopenharmony_ci .start = cvmx_build_io_address(8, 0), 4188c2ecf20Sopenharmony_ci .end = cvmx_build_io_address(8, 0) + 0x7 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci }; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci pd = platform_device_alloc("octeon_rng", -1); 4238c2ecf20Sopenharmony_ci if (!pd) { 4248c2ecf20Sopenharmony_ci ret = -ENOMEM; 4258c2ecf20Sopenharmony_ci goto out; 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci ret = platform_device_add_resources(pd, rng_resources, 4298c2ecf20Sopenharmony_ci ARRAY_SIZE(rng_resources)); 4308c2ecf20Sopenharmony_ci if (ret) 4318c2ecf20Sopenharmony_ci goto fail; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci ret = platform_device_add(pd); 4348c2ecf20Sopenharmony_ci if (ret) 4358c2ecf20Sopenharmony_ci goto fail; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci return ret; 4388c2ecf20Sopenharmony_cifail: 4398c2ecf20Sopenharmony_ci platform_device_put(pd); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ciout: 4428c2ecf20Sopenharmony_ci return ret; 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_cidevice_initcall(octeon_rng_device_init); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_cistatic const struct of_device_id octeon_ids[] __initconst = { 4478c2ecf20Sopenharmony_ci { .compatible = "simple-bus", }, 4488c2ecf20Sopenharmony_ci { .compatible = "cavium,octeon-6335-uctl", }, 4498c2ecf20Sopenharmony_ci { .compatible = "cavium,octeon-5750-usbn", }, 4508c2ecf20Sopenharmony_ci { .compatible = "cavium,octeon-3860-bootbus", }, 4518c2ecf20Sopenharmony_ci { .compatible = "cavium,mdio-mux", }, 4528c2ecf20Sopenharmony_ci { .compatible = "gpio-leds", }, 4538c2ecf20Sopenharmony_ci { .compatible = "cavium,octeon-7130-usb-uctl", }, 4548c2ecf20Sopenharmony_ci {}, 4558c2ecf20Sopenharmony_ci}; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_cistatic bool __init octeon_has_88e1145(void) 4588c2ecf20Sopenharmony_ci{ 4598c2ecf20Sopenharmony_ci return !OCTEON_IS_MODEL(OCTEON_CN52XX) && 4608c2ecf20Sopenharmony_ci !OCTEON_IS_MODEL(OCTEON_CN6XXX) && 4618c2ecf20Sopenharmony_ci !OCTEON_IS_MODEL(OCTEON_CN56XX); 4628c2ecf20Sopenharmony_ci} 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_cistatic bool __init octeon_has_fixed_link(int ipd_port) 4658c2ecf20Sopenharmony_ci{ 4668c2ecf20Sopenharmony_ci switch (cvmx_sysinfo_get()->board_type) { 4678c2ecf20Sopenharmony_ci case CVMX_BOARD_TYPE_CN3005_EVB_HS5: 4688c2ecf20Sopenharmony_ci case CVMX_BOARD_TYPE_CN3010_EVB_HS5: 4698c2ecf20Sopenharmony_ci case CVMX_BOARD_TYPE_CN3020_EVB_HS5: 4708c2ecf20Sopenharmony_ci case CVMX_BOARD_TYPE_CUST_NB5: 4718c2ecf20Sopenharmony_ci case CVMX_BOARD_TYPE_EBH3100: 4728c2ecf20Sopenharmony_ci /* Port 1 on these boards is always gigabit. */ 4738c2ecf20Sopenharmony_ci return ipd_port == 1; 4748c2ecf20Sopenharmony_ci case CVMX_BOARD_TYPE_BBGW_REF: 4758c2ecf20Sopenharmony_ci /* Ports 0 and 1 connect to the switch. */ 4768c2ecf20Sopenharmony_ci return ipd_port == 0 || ipd_port == 1; 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci return false; 4798c2ecf20Sopenharmony_ci} 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_cistatic void __init octeon_fdt_set_phy(int eth, int phy_addr) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci const __be32 *phy_handle; 4848c2ecf20Sopenharmony_ci const __be32 *alt_phy_handle; 4858c2ecf20Sopenharmony_ci const __be32 *reg; 4868c2ecf20Sopenharmony_ci u32 phandle; 4878c2ecf20Sopenharmony_ci int phy; 4888c2ecf20Sopenharmony_ci int alt_phy; 4898c2ecf20Sopenharmony_ci const char *p; 4908c2ecf20Sopenharmony_ci int current_len; 4918c2ecf20Sopenharmony_ci char new_name[20]; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci phy_handle = fdt_getprop(initial_boot_params, eth, "phy-handle", NULL); 4948c2ecf20Sopenharmony_ci if (!phy_handle) 4958c2ecf20Sopenharmony_ci return; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci phandle = be32_to_cpup(phy_handle); 4988c2ecf20Sopenharmony_ci phy = fdt_node_offset_by_phandle(initial_boot_params, phandle); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci alt_phy_handle = fdt_getprop(initial_boot_params, eth, "cavium,alt-phy-handle", NULL); 5018c2ecf20Sopenharmony_ci if (alt_phy_handle) { 5028c2ecf20Sopenharmony_ci u32 alt_phandle = be32_to_cpup(alt_phy_handle); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci alt_phy = fdt_node_offset_by_phandle(initial_boot_params, alt_phandle); 5058c2ecf20Sopenharmony_ci } else { 5068c2ecf20Sopenharmony_ci alt_phy = -1; 5078c2ecf20Sopenharmony_ci } 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci if (phy_addr < 0 || phy < 0) { 5108c2ecf20Sopenharmony_ci /* Delete the PHY things */ 5118c2ecf20Sopenharmony_ci fdt_nop_property(initial_boot_params, eth, "phy-handle"); 5128c2ecf20Sopenharmony_ci /* This one may fail */ 5138c2ecf20Sopenharmony_ci fdt_nop_property(initial_boot_params, eth, "cavium,alt-phy-handle"); 5148c2ecf20Sopenharmony_ci if (phy >= 0) 5158c2ecf20Sopenharmony_ci fdt_nop_node(initial_boot_params, phy); 5168c2ecf20Sopenharmony_ci if (alt_phy >= 0) 5178c2ecf20Sopenharmony_ci fdt_nop_node(initial_boot_params, alt_phy); 5188c2ecf20Sopenharmony_ci return; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci if (phy_addr >= 256 && alt_phy > 0) { 5228c2ecf20Sopenharmony_ci const struct fdt_property *phy_prop; 5238c2ecf20Sopenharmony_ci struct fdt_property *alt_prop; 5248c2ecf20Sopenharmony_ci fdt32_t phy_handle_name; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci /* Use the alt phy node instead.*/ 5278c2ecf20Sopenharmony_ci phy_prop = fdt_get_property(initial_boot_params, eth, "phy-handle", NULL); 5288c2ecf20Sopenharmony_ci phy_handle_name = phy_prop->nameoff; 5298c2ecf20Sopenharmony_ci fdt_nop_node(initial_boot_params, phy); 5308c2ecf20Sopenharmony_ci fdt_nop_property(initial_boot_params, eth, "phy-handle"); 5318c2ecf20Sopenharmony_ci alt_prop = fdt_get_property_w(initial_boot_params, eth, "cavium,alt-phy-handle", NULL); 5328c2ecf20Sopenharmony_ci alt_prop->nameoff = phy_handle_name; 5338c2ecf20Sopenharmony_ci phy = alt_phy; 5348c2ecf20Sopenharmony_ci } 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci phy_addr &= 0xff; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci if (octeon_has_88e1145()) { 5398c2ecf20Sopenharmony_ci fdt_nop_property(initial_boot_params, phy, "marvell,reg-init"); 5408c2ecf20Sopenharmony_ci memset(new_name, 0, sizeof(new_name)); 5418c2ecf20Sopenharmony_ci strcpy(new_name, "marvell,88e1145"); 5428c2ecf20Sopenharmony_ci p = fdt_getprop(initial_boot_params, phy, "compatible", 5438c2ecf20Sopenharmony_ci ¤t_len); 5448c2ecf20Sopenharmony_ci if (p && current_len >= strlen(new_name)) 5458c2ecf20Sopenharmony_ci fdt_setprop_inplace(initial_boot_params, phy, 5468c2ecf20Sopenharmony_ci "compatible", new_name, current_len); 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci reg = fdt_getprop(initial_boot_params, phy, "reg", NULL); 5508c2ecf20Sopenharmony_ci if (phy_addr == be32_to_cpup(reg)) 5518c2ecf20Sopenharmony_ci return; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci fdt_setprop_inplace_cell(initial_boot_params, phy, "reg", phy_addr); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci snprintf(new_name, sizeof(new_name), "ethernet-phy@%x", phy_addr); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci p = fdt_get_name(initial_boot_params, phy, ¤t_len); 5588c2ecf20Sopenharmony_ci if (p && current_len == strlen(new_name)) 5598c2ecf20Sopenharmony_ci fdt_set_name(initial_boot_params, phy, new_name); 5608c2ecf20Sopenharmony_ci else 5618c2ecf20Sopenharmony_ci pr_err("Error: could not rename ethernet phy: <%s>", p); 5628c2ecf20Sopenharmony_ci} 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_cistatic void __init octeon_fdt_set_mac_addr(int n, u64 *pmac) 5658c2ecf20Sopenharmony_ci{ 5668c2ecf20Sopenharmony_ci const u8 *old_mac; 5678c2ecf20Sopenharmony_ci int old_len; 5688c2ecf20Sopenharmony_ci u8 new_mac[6]; 5698c2ecf20Sopenharmony_ci u64 mac = *pmac; 5708c2ecf20Sopenharmony_ci int r; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci old_mac = fdt_getprop(initial_boot_params, n, "local-mac-address", 5738c2ecf20Sopenharmony_ci &old_len); 5748c2ecf20Sopenharmony_ci if (!old_mac || old_len != 6 || is_valid_ether_addr(old_mac)) 5758c2ecf20Sopenharmony_ci return; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci new_mac[0] = (mac >> 40) & 0xff; 5788c2ecf20Sopenharmony_ci new_mac[1] = (mac >> 32) & 0xff; 5798c2ecf20Sopenharmony_ci new_mac[2] = (mac >> 24) & 0xff; 5808c2ecf20Sopenharmony_ci new_mac[3] = (mac >> 16) & 0xff; 5818c2ecf20Sopenharmony_ci new_mac[4] = (mac >> 8) & 0xff; 5828c2ecf20Sopenharmony_ci new_mac[5] = mac & 0xff; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci r = fdt_setprop_inplace(initial_boot_params, n, "local-mac-address", 5858c2ecf20Sopenharmony_ci new_mac, sizeof(new_mac)); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci if (r) { 5888c2ecf20Sopenharmony_ci pr_err("Setting \"local-mac-address\" failed %d", r); 5898c2ecf20Sopenharmony_ci return; 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci *pmac = mac + 1; 5928c2ecf20Sopenharmony_ci} 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_cistatic void __init octeon_fdt_rm_ethernet(int node) 5958c2ecf20Sopenharmony_ci{ 5968c2ecf20Sopenharmony_ci const __be32 *phy_handle; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci phy_handle = fdt_getprop(initial_boot_params, node, "phy-handle", NULL); 5998c2ecf20Sopenharmony_ci if (phy_handle) { 6008c2ecf20Sopenharmony_ci u32 ph = be32_to_cpup(phy_handle); 6018c2ecf20Sopenharmony_ci int p = fdt_node_offset_by_phandle(initial_boot_params, ph); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci if (p >= 0) 6048c2ecf20Sopenharmony_ci fdt_nop_node(initial_boot_params, p); 6058c2ecf20Sopenharmony_ci } 6068c2ecf20Sopenharmony_ci fdt_nop_node(initial_boot_params, node); 6078c2ecf20Sopenharmony_ci} 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_cistatic void __init _octeon_rx_tx_delay(int eth, int rx_delay, int tx_delay) 6108c2ecf20Sopenharmony_ci{ 6118c2ecf20Sopenharmony_ci fdt_setprop_inplace_cell(initial_boot_params, eth, "rx-delay", 6128c2ecf20Sopenharmony_ci rx_delay); 6138c2ecf20Sopenharmony_ci fdt_setprop_inplace_cell(initial_boot_params, eth, "tx-delay", 6148c2ecf20Sopenharmony_ci tx_delay); 6158c2ecf20Sopenharmony_ci} 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_cistatic void __init octeon_rx_tx_delay(int eth, int iface, int port) 6188c2ecf20Sopenharmony_ci{ 6198c2ecf20Sopenharmony_ci switch (cvmx_sysinfo_get()->board_type) { 6208c2ecf20Sopenharmony_ci case CVMX_BOARD_TYPE_CN3005_EVB_HS5: 6218c2ecf20Sopenharmony_ci if (iface == 0) { 6228c2ecf20Sopenharmony_ci if (port == 0) { 6238c2ecf20Sopenharmony_ci /* 6248c2ecf20Sopenharmony_ci * Boards with gigabit WAN ports need a 6258c2ecf20Sopenharmony_ci * different setting that is compatible with 6268c2ecf20Sopenharmony_ci * 100 Mbit settings 6278c2ecf20Sopenharmony_ci */ 6288c2ecf20Sopenharmony_ci _octeon_rx_tx_delay(eth, 0xc, 0x0c); 6298c2ecf20Sopenharmony_ci return; 6308c2ecf20Sopenharmony_ci } else if (port == 1) { 6318c2ecf20Sopenharmony_ci /* Different config for switch port. */ 6328c2ecf20Sopenharmony_ci _octeon_rx_tx_delay(eth, 0x0, 0x0); 6338c2ecf20Sopenharmony_ci return; 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci } 6368c2ecf20Sopenharmony_ci break; 6378c2ecf20Sopenharmony_ci case CVMX_BOARD_TYPE_UBNT_E100: 6388c2ecf20Sopenharmony_ci if (iface == 0 && port <= 2) { 6398c2ecf20Sopenharmony_ci _octeon_rx_tx_delay(eth, 0x0, 0x10); 6408c2ecf20Sopenharmony_ci return; 6418c2ecf20Sopenharmony_ci } 6428c2ecf20Sopenharmony_ci break; 6438c2ecf20Sopenharmony_ci } 6448c2ecf20Sopenharmony_ci fdt_nop_property(initial_boot_params, eth, "rx-delay"); 6458c2ecf20Sopenharmony_ci fdt_nop_property(initial_boot_params, eth, "tx-delay"); 6468c2ecf20Sopenharmony_ci} 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_cistatic void __init octeon_fdt_pip_port(int iface, int i, int p, int max) 6498c2ecf20Sopenharmony_ci{ 6508c2ecf20Sopenharmony_ci char name_buffer[20]; 6518c2ecf20Sopenharmony_ci int eth; 6528c2ecf20Sopenharmony_ci int phy_addr; 6538c2ecf20Sopenharmony_ci int ipd_port; 6548c2ecf20Sopenharmony_ci int fixed_link; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci snprintf(name_buffer, sizeof(name_buffer), "ethernet@%x", p); 6578c2ecf20Sopenharmony_ci eth = fdt_subnode_offset(initial_boot_params, iface, name_buffer); 6588c2ecf20Sopenharmony_ci if (eth < 0) 6598c2ecf20Sopenharmony_ci return; 6608c2ecf20Sopenharmony_ci if (p > max) { 6618c2ecf20Sopenharmony_ci pr_debug("Deleting port %x:%x\n", i, p); 6628c2ecf20Sopenharmony_ci octeon_fdt_rm_ethernet(eth); 6638c2ecf20Sopenharmony_ci return; 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN68XX)) 6668c2ecf20Sopenharmony_ci ipd_port = (0x100 * i) + (0x10 * p) + 0x800; 6678c2ecf20Sopenharmony_ci else 6688c2ecf20Sopenharmony_ci ipd_port = 16 * i + p; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci phy_addr = cvmx_helper_board_get_mii_address(ipd_port); 6718c2ecf20Sopenharmony_ci octeon_fdt_set_phy(eth, phy_addr); 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci fixed_link = fdt_subnode_offset(initial_boot_params, eth, "fixed-link"); 6748c2ecf20Sopenharmony_ci if (fixed_link < 0) 6758c2ecf20Sopenharmony_ci WARN_ON(octeon_has_fixed_link(ipd_port)); 6768c2ecf20Sopenharmony_ci else if (!octeon_has_fixed_link(ipd_port)) 6778c2ecf20Sopenharmony_ci fdt_nop_node(initial_boot_params, fixed_link); 6788c2ecf20Sopenharmony_ci octeon_rx_tx_delay(eth, i, p); 6798c2ecf20Sopenharmony_ci} 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_cistatic void __init octeon_fdt_pip_iface(int pip, int idx) 6828c2ecf20Sopenharmony_ci{ 6838c2ecf20Sopenharmony_ci char name_buffer[20]; 6848c2ecf20Sopenharmony_ci int iface; 6858c2ecf20Sopenharmony_ci int p; 6868c2ecf20Sopenharmony_ci int count = 0; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci snprintf(name_buffer, sizeof(name_buffer), "interface@%d", idx); 6898c2ecf20Sopenharmony_ci iface = fdt_subnode_offset(initial_boot_params, pip, name_buffer); 6908c2ecf20Sopenharmony_ci if (iface < 0) 6918c2ecf20Sopenharmony_ci return; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci if (cvmx_helper_interface_enumerate(idx) == 0) 6948c2ecf20Sopenharmony_ci count = cvmx_helper_ports_on_interface(idx); 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci for (p = 0; p < 16; p++) 6978c2ecf20Sopenharmony_ci octeon_fdt_pip_port(iface, idx, p, count - 1); 6988c2ecf20Sopenharmony_ci} 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_civoid __init octeon_fill_mac_addresses(void) 7018c2ecf20Sopenharmony_ci{ 7028c2ecf20Sopenharmony_ci const char *alias_prop; 7038c2ecf20Sopenharmony_ci char name_buffer[20]; 7048c2ecf20Sopenharmony_ci u64 mac_addr_base; 7058c2ecf20Sopenharmony_ci int aliases; 7068c2ecf20Sopenharmony_ci int pip; 7078c2ecf20Sopenharmony_ci int i; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci aliases = fdt_path_offset(initial_boot_params, "/aliases"); 7108c2ecf20Sopenharmony_ci if (aliases < 0) 7118c2ecf20Sopenharmony_ci return; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci mac_addr_base = 7148c2ecf20Sopenharmony_ci ((octeon_bootinfo->mac_addr_base[0] & 0xffull)) << 40 | 7158c2ecf20Sopenharmony_ci ((octeon_bootinfo->mac_addr_base[1] & 0xffull)) << 32 | 7168c2ecf20Sopenharmony_ci ((octeon_bootinfo->mac_addr_base[2] & 0xffull)) << 24 | 7178c2ecf20Sopenharmony_ci ((octeon_bootinfo->mac_addr_base[3] & 0xffull)) << 16 | 7188c2ecf20Sopenharmony_ci ((octeon_bootinfo->mac_addr_base[4] & 0xffull)) << 8 | 7198c2ecf20Sopenharmony_ci (octeon_bootinfo->mac_addr_base[5] & 0xffull); 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 7228c2ecf20Sopenharmony_ci int mgmt; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci snprintf(name_buffer, sizeof(name_buffer), "mix%d", i); 7258c2ecf20Sopenharmony_ci alias_prop = fdt_getprop(initial_boot_params, aliases, 7268c2ecf20Sopenharmony_ci name_buffer, NULL); 7278c2ecf20Sopenharmony_ci if (!alias_prop) 7288c2ecf20Sopenharmony_ci continue; 7298c2ecf20Sopenharmony_ci mgmt = fdt_path_offset(initial_boot_params, alias_prop); 7308c2ecf20Sopenharmony_ci if (mgmt < 0) 7318c2ecf20Sopenharmony_ci continue; 7328c2ecf20Sopenharmony_ci octeon_fdt_set_mac_addr(mgmt, &mac_addr_base); 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci alias_prop = fdt_getprop(initial_boot_params, aliases, "pip", NULL); 7368c2ecf20Sopenharmony_ci if (!alias_prop) 7378c2ecf20Sopenharmony_ci return; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci pip = fdt_path_offset(initial_boot_params, alias_prop); 7408c2ecf20Sopenharmony_ci if (pip < 0) 7418c2ecf20Sopenharmony_ci return; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci for (i = 0; i <= 4; i++) { 7448c2ecf20Sopenharmony_ci int iface; 7458c2ecf20Sopenharmony_ci int p; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci snprintf(name_buffer, sizeof(name_buffer), "interface@%d", i); 7488c2ecf20Sopenharmony_ci iface = fdt_subnode_offset(initial_boot_params, pip, 7498c2ecf20Sopenharmony_ci name_buffer); 7508c2ecf20Sopenharmony_ci if (iface < 0) 7518c2ecf20Sopenharmony_ci continue; 7528c2ecf20Sopenharmony_ci for (p = 0; p < 16; p++) { 7538c2ecf20Sopenharmony_ci int eth; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci snprintf(name_buffer, sizeof(name_buffer), 7568c2ecf20Sopenharmony_ci "ethernet@%x", p); 7578c2ecf20Sopenharmony_ci eth = fdt_subnode_offset(initial_boot_params, iface, 7588c2ecf20Sopenharmony_ci name_buffer); 7598c2ecf20Sopenharmony_ci if (eth < 0) 7608c2ecf20Sopenharmony_ci continue; 7618c2ecf20Sopenharmony_ci octeon_fdt_set_mac_addr(eth, &mac_addr_base); 7628c2ecf20Sopenharmony_ci } 7638c2ecf20Sopenharmony_ci } 7648c2ecf20Sopenharmony_ci} 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ciint __init octeon_prune_device_tree(void) 7678c2ecf20Sopenharmony_ci{ 7688c2ecf20Sopenharmony_ci int i, max_port, uart_mask; 7698c2ecf20Sopenharmony_ci const char *pip_path; 7708c2ecf20Sopenharmony_ci const char *alias_prop; 7718c2ecf20Sopenharmony_ci char name_buffer[20]; 7728c2ecf20Sopenharmony_ci int aliases; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci if (fdt_check_header(initial_boot_params)) 7758c2ecf20Sopenharmony_ci panic("Corrupt Device Tree."); 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci WARN(octeon_bootinfo->board_type == CVMX_BOARD_TYPE_CUST_DSR1000N, 7788c2ecf20Sopenharmony_ci "Built-in DTB booting is deprecated on %s. Please switch to use appended DTB.", 7798c2ecf20Sopenharmony_ci cvmx_board_type_to_string(octeon_bootinfo->board_type)); 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci aliases = fdt_path_offset(initial_boot_params, "/aliases"); 7828c2ecf20Sopenharmony_ci if (aliases < 0) { 7838c2ecf20Sopenharmony_ci pr_err("Error: No /aliases node in device tree."); 7848c2ecf20Sopenharmony_ci return -EINVAL; 7858c2ecf20Sopenharmony_ci } 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN52XX) || OCTEON_IS_MODEL(OCTEON_CN63XX)) 7888c2ecf20Sopenharmony_ci max_port = 2; 7898c2ecf20Sopenharmony_ci else if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN68XX)) 7908c2ecf20Sopenharmony_ci max_port = 1; 7918c2ecf20Sopenharmony_ci else 7928c2ecf20Sopenharmony_ci max_port = 0; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci if (octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC10E) 7958c2ecf20Sopenharmony_ci max_port = 0; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 7988c2ecf20Sopenharmony_ci int mgmt; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci snprintf(name_buffer, sizeof(name_buffer), 8018c2ecf20Sopenharmony_ci "mix%d", i); 8028c2ecf20Sopenharmony_ci alias_prop = fdt_getprop(initial_boot_params, aliases, 8038c2ecf20Sopenharmony_ci name_buffer, NULL); 8048c2ecf20Sopenharmony_ci if (alias_prop) { 8058c2ecf20Sopenharmony_ci mgmt = fdt_path_offset(initial_boot_params, alias_prop); 8068c2ecf20Sopenharmony_ci if (mgmt < 0) 8078c2ecf20Sopenharmony_ci continue; 8088c2ecf20Sopenharmony_ci if (i >= max_port) { 8098c2ecf20Sopenharmony_ci pr_debug("Deleting mix%d\n", i); 8108c2ecf20Sopenharmony_ci octeon_fdt_rm_ethernet(mgmt); 8118c2ecf20Sopenharmony_ci fdt_nop_property(initial_boot_params, aliases, 8128c2ecf20Sopenharmony_ci name_buffer); 8138c2ecf20Sopenharmony_ci } else { 8148c2ecf20Sopenharmony_ci int phy_addr = cvmx_helper_board_get_mii_address(CVMX_HELPER_BOARD_MGMT_IPD_PORT + i); 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci octeon_fdt_set_phy(mgmt, phy_addr); 8178c2ecf20Sopenharmony_ci } 8188c2ecf20Sopenharmony_ci } 8198c2ecf20Sopenharmony_ci } 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci pip_path = fdt_getprop(initial_boot_params, aliases, "pip", NULL); 8228c2ecf20Sopenharmony_ci if (pip_path) { 8238c2ecf20Sopenharmony_ci int pip = fdt_path_offset(initial_boot_params, pip_path); 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci if (pip >= 0) 8268c2ecf20Sopenharmony_ci for (i = 0; i <= 4; i++) 8278c2ecf20Sopenharmony_ci octeon_fdt_pip_iface(pip, i); 8288c2ecf20Sopenharmony_ci } 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci /* I2C */ 8318c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN52XX) || 8328c2ecf20Sopenharmony_ci OCTEON_IS_MODEL(OCTEON_CN63XX) || 8338c2ecf20Sopenharmony_ci OCTEON_IS_MODEL(OCTEON_CN68XX) || 8348c2ecf20Sopenharmony_ci OCTEON_IS_MODEL(OCTEON_CN56XX)) 8358c2ecf20Sopenharmony_ci max_port = 2; 8368c2ecf20Sopenharmony_ci else 8378c2ecf20Sopenharmony_ci max_port = 1; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 8408c2ecf20Sopenharmony_ci int i2c; 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci snprintf(name_buffer, sizeof(name_buffer), 8438c2ecf20Sopenharmony_ci "twsi%d", i); 8448c2ecf20Sopenharmony_ci alias_prop = fdt_getprop(initial_boot_params, aliases, 8458c2ecf20Sopenharmony_ci name_buffer, NULL); 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci if (alias_prop) { 8488c2ecf20Sopenharmony_ci i2c = fdt_path_offset(initial_boot_params, alias_prop); 8498c2ecf20Sopenharmony_ci if (i2c < 0) 8508c2ecf20Sopenharmony_ci continue; 8518c2ecf20Sopenharmony_ci if (i >= max_port) { 8528c2ecf20Sopenharmony_ci pr_debug("Deleting twsi%d\n", i); 8538c2ecf20Sopenharmony_ci fdt_nop_node(initial_boot_params, i2c); 8548c2ecf20Sopenharmony_ci fdt_nop_property(initial_boot_params, aliases, 8558c2ecf20Sopenharmony_ci name_buffer); 8568c2ecf20Sopenharmony_ci } 8578c2ecf20Sopenharmony_ci } 8588c2ecf20Sopenharmony_ci } 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci /* SMI/MDIO */ 8618c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN68XX)) 8628c2ecf20Sopenharmony_ci max_port = 4; 8638c2ecf20Sopenharmony_ci else if (OCTEON_IS_MODEL(OCTEON_CN52XX) || 8648c2ecf20Sopenharmony_ci OCTEON_IS_MODEL(OCTEON_CN63XX) || 8658c2ecf20Sopenharmony_ci OCTEON_IS_MODEL(OCTEON_CN56XX)) 8668c2ecf20Sopenharmony_ci max_port = 2; 8678c2ecf20Sopenharmony_ci else 8688c2ecf20Sopenharmony_ci max_port = 1; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 8718c2ecf20Sopenharmony_ci int i2c; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci snprintf(name_buffer, sizeof(name_buffer), 8748c2ecf20Sopenharmony_ci "smi%d", i); 8758c2ecf20Sopenharmony_ci alias_prop = fdt_getprop(initial_boot_params, aliases, 8768c2ecf20Sopenharmony_ci name_buffer, NULL); 8778c2ecf20Sopenharmony_ci if (alias_prop) { 8788c2ecf20Sopenharmony_ci i2c = fdt_path_offset(initial_boot_params, alias_prop); 8798c2ecf20Sopenharmony_ci if (i2c < 0) 8808c2ecf20Sopenharmony_ci continue; 8818c2ecf20Sopenharmony_ci if (i >= max_port) { 8828c2ecf20Sopenharmony_ci pr_debug("Deleting smi%d\n", i); 8838c2ecf20Sopenharmony_ci fdt_nop_node(initial_boot_params, i2c); 8848c2ecf20Sopenharmony_ci fdt_nop_property(initial_boot_params, aliases, 8858c2ecf20Sopenharmony_ci name_buffer); 8868c2ecf20Sopenharmony_ci } 8878c2ecf20Sopenharmony_ci } 8888c2ecf20Sopenharmony_ci } 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci /* Serial */ 8918c2ecf20Sopenharmony_ci uart_mask = 3; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci /* Right now CN52XX is the only chip with a third uart */ 8948c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN52XX)) 8958c2ecf20Sopenharmony_ci uart_mask |= 4; /* uart2 */ 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) { 8988c2ecf20Sopenharmony_ci int uart; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci snprintf(name_buffer, sizeof(name_buffer), 9018c2ecf20Sopenharmony_ci "uart%d", i); 9028c2ecf20Sopenharmony_ci alias_prop = fdt_getprop(initial_boot_params, aliases, 9038c2ecf20Sopenharmony_ci name_buffer, NULL); 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci if (alias_prop) { 9068c2ecf20Sopenharmony_ci uart = fdt_path_offset(initial_boot_params, alias_prop); 9078c2ecf20Sopenharmony_ci if (uart_mask & (1 << i)) { 9088c2ecf20Sopenharmony_ci __be32 f; 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci f = cpu_to_be32(octeon_get_io_clock_rate()); 9118c2ecf20Sopenharmony_ci fdt_setprop_inplace(initial_boot_params, 9128c2ecf20Sopenharmony_ci uart, "clock-frequency", 9138c2ecf20Sopenharmony_ci &f, sizeof(f)); 9148c2ecf20Sopenharmony_ci continue; 9158c2ecf20Sopenharmony_ci } 9168c2ecf20Sopenharmony_ci pr_debug("Deleting uart%d\n", i); 9178c2ecf20Sopenharmony_ci fdt_nop_node(initial_boot_params, uart); 9188c2ecf20Sopenharmony_ci fdt_nop_property(initial_boot_params, aliases, 9198c2ecf20Sopenharmony_ci name_buffer); 9208c2ecf20Sopenharmony_ci } 9218c2ecf20Sopenharmony_ci } 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci /* Compact Flash */ 9248c2ecf20Sopenharmony_ci alias_prop = fdt_getprop(initial_boot_params, aliases, 9258c2ecf20Sopenharmony_ci "cf0", NULL); 9268c2ecf20Sopenharmony_ci if (alias_prop) { 9278c2ecf20Sopenharmony_ci union cvmx_mio_boot_reg_cfgx mio_boot_reg_cfg; 9288c2ecf20Sopenharmony_ci unsigned long base_ptr, region_base, region_size; 9298c2ecf20Sopenharmony_ci unsigned long region1_base = 0; 9308c2ecf20Sopenharmony_ci unsigned long region1_size = 0; 9318c2ecf20Sopenharmony_ci int cs, bootbus; 9328c2ecf20Sopenharmony_ci bool is_16bit = false; 9338c2ecf20Sopenharmony_ci bool is_true_ide = false; 9348c2ecf20Sopenharmony_ci __be32 new_reg[6]; 9358c2ecf20Sopenharmony_ci __be32 *ranges; 9368c2ecf20Sopenharmony_ci int len; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci int cf = fdt_path_offset(initial_boot_params, alias_prop); 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci base_ptr = 0; 9418c2ecf20Sopenharmony_ci if (octeon_bootinfo->major_version == 1 9428c2ecf20Sopenharmony_ci && octeon_bootinfo->minor_version >= 1) { 9438c2ecf20Sopenharmony_ci if (octeon_bootinfo->compact_flash_common_base_addr) 9448c2ecf20Sopenharmony_ci base_ptr = octeon_bootinfo->compact_flash_common_base_addr; 9458c2ecf20Sopenharmony_ci } else { 9468c2ecf20Sopenharmony_ci base_ptr = 0x1d000800; 9478c2ecf20Sopenharmony_ci } 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci if (!base_ptr) 9508c2ecf20Sopenharmony_ci goto no_cf; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci /* Find CS0 region. */ 9538c2ecf20Sopenharmony_ci for (cs = 0; cs < 8; cs++) { 9548c2ecf20Sopenharmony_ci mio_boot_reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs)); 9558c2ecf20Sopenharmony_ci region_base = mio_boot_reg_cfg.s.base << 16; 9568c2ecf20Sopenharmony_ci region_size = (mio_boot_reg_cfg.s.size + 1) << 16; 9578c2ecf20Sopenharmony_ci if (mio_boot_reg_cfg.s.en && base_ptr >= region_base 9588c2ecf20Sopenharmony_ci && base_ptr < region_base + region_size) { 9598c2ecf20Sopenharmony_ci is_16bit = mio_boot_reg_cfg.s.width; 9608c2ecf20Sopenharmony_ci break; 9618c2ecf20Sopenharmony_ci } 9628c2ecf20Sopenharmony_ci } 9638c2ecf20Sopenharmony_ci if (cs >= 7) { 9648c2ecf20Sopenharmony_ci /* cs and cs + 1 are CS0 and CS1, both must be less than 8. */ 9658c2ecf20Sopenharmony_ci goto no_cf; 9668c2ecf20Sopenharmony_ci } 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci if (!(base_ptr & 0xfffful)) { 9698c2ecf20Sopenharmony_ci /* 9708c2ecf20Sopenharmony_ci * Boot loader signals availability of DMA (true_ide 9718c2ecf20Sopenharmony_ci * mode) by setting low order bits of base_ptr to 9728c2ecf20Sopenharmony_ci * zero. 9738c2ecf20Sopenharmony_ci */ 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci /* Asume that CS1 immediately follows. */ 9768c2ecf20Sopenharmony_ci mio_boot_reg_cfg.u64 = 9778c2ecf20Sopenharmony_ci cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs + 1)); 9788c2ecf20Sopenharmony_ci region1_base = mio_boot_reg_cfg.s.base << 16; 9798c2ecf20Sopenharmony_ci region1_size = (mio_boot_reg_cfg.s.size + 1) << 16; 9808c2ecf20Sopenharmony_ci if (!mio_boot_reg_cfg.s.en) 9818c2ecf20Sopenharmony_ci goto no_cf; 9828c2ecf20Sopenharmony_ci is_true_ide = true; 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci } else { 9858c2ecf20Sopenharmony_ci fdt_nop_property(initial_boot_params, cf, "cavium,true-ide"); 9868c2ecf20Sopenharmony_ci fdt_nop_property(initial_boot_params, cf, "cavium,dma-engine-handle"); 9878c2ecf20Sopenharmony_ci if (!is_16bit) { 9888c2ecf20Sopenharmony_ci __be32 width = cpu_to_be32(8); 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci fdt_setprop_inplace(initial_boot_params, cf, 9918c2ecf20Sopenharmony_ci "cavium,bus-width", &width, sizeof(width)); 9928c2ecf20Sopenharmony_ci } 9938c2ecf20Sopenharmony_ci } 9948c2ecf20Sopenharmony_ci new_reg[0] = cpu_to_be32(cs); 9958c2ecf20Sopenharmony_ci new_reg[1] = cpu_to_be32(0); 9968c2ecf20Sopenharmony_ci new_reg[2] = cpu_to_be32(0x10000); 9978c2ecf20Sopenharmony_ci new_reg[3] = cpu_to_be32(cs + 1); 9988c2ecf20Sopenharmony_ci new_reg[4] = cpu_to_be32(0); 9998c2ecf20Sopenharmony_ci new_reg[5] = cpu_to_be32(0x10000); 10008c2ecf20Sopenharmony_ci fdt_setprop_inplace(initial_boot_params, cf, 10018c2ecf20Sopenharmony_ci "reg", new_reg, sizeof(new_reg)); 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci bootbus = fdt_parent_offset(initial_boot_params, cf); 10048c2ecf20Sopenharmony_ci if (bootbus < 0) 10058c2ecf20Sopenharmony_ci goto no_cf; 10068c2ecf20Sopenharmony_ci ranges = fdt_getprop_w(initial_boot_params, bootbus, "ranges", &len); 10078c2ecf20Sopenharmony_ci if (!ranges || len < (5 * 8 * sizeof(__be32))) 10088c2ecf20Sopenharmony_ci goto no_cf; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci ranges[(cs * 5) + 2] = cpu_to_be32(region_base >> 32); 10118c2ecf20Sopenharmony_ci ranges[(cs * 5) + 3] = cpu_to_be32(region_base & 0xffffffff); 10128c2ecf20Sopenharmony_ci ranges[(cs * 5) + 4] = cpu_to_be32(region_size); 10138c2ecf20Sopenharmony_ci if (is_true_ide) { 10148c2ecf20Sopenharmony_ci cs++; 10158c2ecf20Sopenharmony_ci ranges[(cs * 5) + 2] = cpu_to_be32(region1_base >> 32); 10168c2ecf20Sopenharmony_ci ranges[(cs * 5) + 3] = cpu_to_be32(region1_base & 0xffffffff); 10178c2ecf20Sopenharmony_ci ranges[(cs * 5) + 4] = cpu_to_be32(region1_size); 10188c2ecf20Sopenharmony_ci } 10198c2ecf20Sopenharmony_ci goto end_cf; 10208c2ecf20Sopenharmony_cino_cf: 10218c2ecf20Sopenharmony_ci fdt_nop_node(initial_boot_params, cf); 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ciend_cf: 10248c2ecf20Sopenharmony_ci ; 10258c2ecf20Sopenharmony_ci } 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci /* 8 char LED */ 10288c2ecf20Sopenharmony_ci alias_prop = fdt_getprop(initial_boot_params, aliases, 10298c2ecf20Sopenharmony_ci "led0", NULL); 10308c2ecf20Sopenharmony_ci if (alias_prop) { 10318c2ecf20Sopenharmony_ci union cvmx_mio_boot_reg_cfgx mio_boot_reg_cfg; 10328c2ecf20Sopenharmony_ci unsigned long base_ptr, region_base, region_size; 10338c2ecf20Sopenharmony_ci int cs, bootbus; 10348c2ecf20Sopenharmony_ci __be32 new_reg[6]; 10358c2ecf20Sopenharmony_ci __be32 *ranges; 10368c2ecf20Sopenharmony_ci int len; 10378c2ecf20Sopenharmony_ci int led = fdt_path_offset(initial_boot_params, alias_prop); 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci base_ptr = octeon_bootinfo->led_display_base_addr; 10408c2ecf20Sopenharmony_ci if (base_ptr == 0) 10418c2ecf20Sopenharmony_ci goto no_led; 10428c2ecf20Sopenharmony_ci /* Find CS0 region. */ 10438c2ecf20Sopenharmony_ci for (cs = 0; cs < 8; cs++) { 10448c2ecf20Sopenharmony_ci mio_boot_reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs)); 10458c2ecf20Sopenharmony_ci region_base = mio_boot_reg_cfg.s.base << 16; 10468c2ecf20Sopenharmony_ci region_size = (mio_boot_reg_cfg.s.size + 1) << 16; 10478c2ecf20Sopenharmony_ci if (mio_boot_reg_cfg.s.en && base_ptr >= region_base 10488c2ecf20Sopenharmony_ci && base_ptr < region_base + region_size) 10498c2ecf20Sopenharmony_ci break; 10508c2ecf20Sopenharmony_ci } 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci if (cs > 7) 10538c2ecf20Sopenharmony_ci goto no_led; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci new_reg[0] = cpu_to_be32(cs); 10568c2ecf20Sopenharmony_ci new_reg[1] = cpu_to_be32(0x20); 10578c2ecf20Sopenharmony_ci new_reg[2] = cpu_to_be32(0x20); 10588c2ecf20Sopenharmony_ci new_reg[3] = cpu_to_be32(cs); 10598c2ecf20Sopenharmony_ci new_reg[4] = cpu_to_be32(0); 10608c2ecf20Sopenharmony_ci new_reg[5] = cpu_to_be32(0x20); 10618c2ecf20Sopenharmony_ci fdt_setprop_inplace(initial_boot_params, led, 10628c2ecf20Sopenharmony_ci "reg", new_reg, sizeof(new_reg)); 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci bootbus = fdt_parent_offset(initial_boot_params, led); 10658c2ecf20Sopenharmony_ci if (bootbus < 0) 10668c2ecf20Sopenharmony_ci goto no_led; 10678c2ecf20Sopenharmony_ci ranges = fdt_getprop_w(initial_boot_params, bootbus, "ranges", &len); 10688c2ecf20Sopenharmony_ci if (!ranges || len < (5 * 8 * sizeof(__be32))) 10698c2ecf20Sopenharmony_ci goto no_led; 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci ranges[(cs * 5) + 2] = cpu_to_be32(region_base >> 32); 10728c2ecf20Sopenharmony_ci ranges[(cs * 5) + 3] = cpu_to_be32(region_base & 0xffffffff); 10738c2ecf20Sopenharmony_ci ranges[(cs * 5) + 4] = cpu_to_be32(region_size); 10748c2ecf20Sopenharmony_ci goto end_led; 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_cino_led: 10778c2ecf20Sopenharmony_ci fdt_nop_node(initial_boot_params, led); 10788c2ecf20Sopenharmony_ciend_led: 10798c2ecf20Sopenharmony_ci ; 10808c2ecf20Sopenharmony_ci } 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci#ifdef CONFIG_USB 10838c2ecf20Sopenharmony_ci /* OHCI/UHCI USB */ 10848c2ecf20Sopenharmony_ci alias_prop = fdt_getprop(initial_boot_params, aliases, 10858c2ecf20Sopenharmony_ci "uctl", NULL); 10868c2ecf20Sopenharmony_ci if (alias_prop) { 10878c2ecf20Sopenharmony_ci int uctl = fdt_path_offset(initial_boot_params, alias_prop); 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci if (uctl >= 0 && (!OCTEON_IS_MODEL(OCTEON_CN6XXX) || 10908c2ecf20Sopenharmony_ci octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC2E)) { 10918c2ecf20Sopenharmony_ci pr_debug("Deleting uctl\n"); 10928c2ecf20Sopenharmony_ci fdt_nop_node(initial_boot_params, uctl); 10938c2ecf20Sopenharmony_ci fdt_nop_property(initial_boot_params, aliases, "uctl"); 10948c2ecf20Sopenharmony_ci } else if (octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC10E || 10958c2ecf20Sopenharmony_ci octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC4E) { 10968c2ecf20Sopenharmony_ci /* Missing "refclk-type" defaults to crystal. */ 10978c2ecf20Sopenharmony_ci fdt_nop_property(initial_boot_params, uctl, "refclk-type"); 10988c2ecf20Sopenharmony_ci } 10998c2ecf20Sopenharmony_ci } 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci /* DWC2 USB */ 11028c2ecf20Sopenharmony_ci alias_prop = fdt_getprop(initial_boot_params, aliases, 11038c2ecf20Sopenharmony_ci "usbn", NULL); 11048c2ecf20Sopenharmony_ci if (alias_prop) { 11058c2ecf20Sopenharmony_ci int usbn = fdt_path_offset(initial_boot_params, alias_prop); 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci if (usbn >= 0 && (current_cpu_type() == CPU_CAVIUM_OCTEON2 || 11088c2ecf20Sopenharmony_ci !octeon_has_feature(OCTEON_FEATURE_USB))) { 11098c2ecf20Sopenharmony_ci pr_debug("Deleting usbn\n"); 11108c2ecf20Sopenharmony_ci fdt_nop_node(initial_boot_params, usbn); 11118c2ecf20Sopenharmony_ci fdt_nop_property(initial_boot_params, aliases, "usbn"); 11128c2ecf20Sopenharmony_ci } else { 11138c2ecf20Sopenharmony_ci __be32 new_f[1]; 11148c2ecf20Sopenharmony_ci enum cvmx_helper_board_usb_clock_types c; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci c = __cvmx_helper_board_usb_get_clock_type(); 11178c2ecf20Sopenharmony_ci switch (c) { 11188c2ecf20Sopenharmony_ci case USB_CLOCK_TYPE_REF_48: 11198c2ecf20Sopenharmony_ci new_f[0] = cpu_to_be32(48000000); 11208c2ecf20Sopenharmony_ci fdt_setprop_inplace(initial_boot_params, usbn, 11218c2ecf20Sopenharmony_ci "refclk-frequency", new_f, sizeof(new_f)); 11228c2ecf20Sopenharmony_ci fallthrough; 11238c2ecf20Sopenharmony_ci case USB_CLOCK_TYPE_REF_12: 11248c2ecf20Sopenharmony_ci /* Missing "refclk-type" defaults to external. */ 11258c2ecf20Sopenharmony_ci fdt_nop_property(initial_boot_params, usbn, "refclk-type"); 11268c2ecf20Sopenharmony_ci break; 11278c2ecf20Sopenharmony_ci default: 11288c2ecf20Sopenharmony_ci break; 11298c2ecf20Sopenharmony_ci } 11308c2ecf20Sopenharmony_ci } 11318c2ecf20Sopenharmony_ci } 11328c2ecf20Sopenharmony_ci#endif 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci return 0; 11358c2ecf20Sopenharmony_ci} 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_cistatic int __init octeon_publish_devices(void) 11388c2ecf20Sopenharmony_ci{ 11398c2ecf20Sopenharmony_ci return of_platform_populate(NULL, octeon_ids, NULL, NULL); 11408c2ecf20Sopenharmony_ci} 11418c2ecf20Sopenharmony_ciarch_initcall(octeon_publish_devices); 1142