1512254baSDavid Daney /* 2512254baSDavid Daney * This file is subject to the terms and conditions of the GNU General Public 3512254baSDavid Daney * License. See the file "COPYING" in the main directory of this archive 4512254baSDavid Daney * for more details. 5512254baSDavid Daney * 67fd57ab9SSteven J. Hill * Copyright (C) 2004-2017 Cavium, Inc. 7512254baSDavid Daney * Copyright (C) 2008 Wind River Systems 8512254baSDavid Daney */ 9512254baSDavid Daney 10377de399SAaro Koskinen #include <linux/etherdevice.h> 117ed18152SDavid Daney #include <linux/of_platform.h> 127ed18152SDavid Daney #include <linux/of_fdt.h> 137ed18152SDavid Daney #include <linux/libfdt.h> 14512254baSDavid Daney 15512254baSDavid Daney #include <asm/octeon/octeon.h> 167ed18152SDavid Daney #include <asm/octeon/cvmx-helper-board.h> 177fd57ab9SSteven J. Hill 187fd57ab9SSteven J. Hill #ifdef CONFIG_USB 197fd57ab9SSteven J. Hill #include <linux/usb/ehci_def.h> 207fd57ab9SSteven J. Hill #include <linux/usb/ehci_pdriver.h> 217fd57ab9SSteven J. Hill #include <linux/usb/ohci_pdriver.h> 222193dda5SAlan Stern #include <asm/octeon/cvmx-uctlx-defs.h> 23512254baSDavid Daney 247e78db99SSteven J. Hill #define CVMX_UAHCX_EHCI_USBCMD (CVMX_ADD_IO_SEG(0x00016F0000000010ull)) 257e78db99SSteven J. Hill #define CVMX_UAHCX_OHCI_USBCMD (CVMX_ADD_IO_SEG(0x00016F0000000408ull)) 267e78db99SSteven J. Hill 272193dda5SAlan Stern static DEFINE_MUTEX(octeon2_usb_clocks_mutex); 282193dda5SAlan Stern 292193dda5SAlan Stern static int octeon2_usb_clock_start_cnt; 302193dda5SAlan Stern 317e78db99SSteven J. Hill static int __init octeon2_usb_reset(void) 327e78db99SSteven J. Hill { 337e78db99SSteven J. Hill union cvmx_uctlx_clk_rst_ctl clk_rst_ctl; 347e78db99SSteven J. Hill u32 ucmd; 357e78db99SSteven J. Hill 367e78db99SSteven J. Hill if (!OCTEON_IS_OCTEON2()) 377e78db99SSteven J. Hill return 0; 387e78db99SSteven J. Hill 397e78db99SSteven J. Hill clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0)); 407e78db99SSteven J. Hill if (clk_rst_ctl.s.hrst) { 417e78db99SSteven J. Hill ucmd = cvmx_read64_uint32(CVMX_UAHCX_EHCI_USBCMD); 427e78db99SSteven J. Hill ucmd &= ~CMD_RUN; 437e78db99SSteven J. Hill cvmx_write64_uint32(CVMX_UAHCX_EHCI_USBCMD, ucmd); 447e78db99SSteven J. Hill mdelay(2); 457e78db99SSteven J. Hill ucmd |= CMD_RESET; 467e78db99SSteven J. Hill cvmx_write64_uint32(CVMX_UAHCX_EHCI_USBCMD, ucmd); 477e78db99SSteven J. Hill ucmd = cvmx_read64_uint32(CVMX_UAHCX_OHCI_USBCMD); 487e78db99SSteven J. Hill ucmd |= CMD_RUN; 497e78db99SSteven J. Hill cvmx_write64_uint32(CVMX_UAHCX_OHCI_USBCMD, ucmd); 507e78db99SSteven J. Hill } 517e78db99SSteven J. Hill 527e78db99SSteven J. Hill return 0; 537e78db99SSteven J. Hill } 547e78db99SSteven J. Hill arch_initcall(octeon2_usb_reset); 557e78db99SSteven J. Hill 56a95cfa6bSAndreas Herrmann static void octeon2_usb_clocks_start(struct device *dev) 572193dda5SAlan Stern { 582193dda5SAlan Stern u64 div; 592193dda5SAlan Stern union cvmx_uctlx_if_ena if_ena; 602193dda5SAlan Stern union cvmx_uctlx_clk_rst_ctl clk_rst_ctl; 612193dda5SAlan Stern union cvmx_uctlx_uphy_portx_ctl_status port_ctl_status; 622193dda5SAlan Stern int i; 632193dda5SAlan Stern unsigned long io_clk_64_to_ns; 64a95cfa6bSAndreas Herrmann u32 clock_rate = 12000000; 65a95cfa6bSAndreas Herrmann bool is_crystal_clock = false; 662193dda5SAlan Stern 672193dda5SAlan Stern 682193dda5SAlan Stern mutex_lock(&octeon2_usb_clocks_mutex); 692193dda5SAlan Stern 702193dda5SAlan Stern octeon2_usb_clock_start_cnt++; 712193dda5SAlan Stern if (octeon2_usb_clock_start_cnt != 1) 722193dda5SAlan Stern goto exit; 732193dda5SAlan Stern 742193dda5SAlan Stern io_clk_64_to_ns = 64000000000ull / octeon_get_io_clock_rate(); 752193dda5SAlan Stern 76a95cfa6bSAndreas Herrmann if (dev->of_node) { 77a95cfa6bSAndreas Herrmann struct device_node *uctl_node; 78a95cfa6bSAndreas Herrmann const char *clock_type; 79a95cfa6bSAndreas Herrmann 80a95cfa6bSAndreas Herrmann uctl_node = of_get_parent(dev->of_node); 81a95cfa6bSAndreas Herrmann if (!uctl_node) { 82a95cfa6bSAndreas Herrmann dev_err(dev, "No UCTL device node\n"); 83a95cfa6bSAndreas Herrmann goto exit; 84a95cfa6bSAndreas Herrmann } 85a95cfa6bSAndreas Herrmann i = of_property_read_u32(uctl_node, 86a95cfa6bSAndreas Herrmann "refclk-frequency", &clock_rate); 87a95cfa6bSAndreas Herrmann if (i) { 88a95cfa6bSAndreas Herrmann dev_err(dev, "No UCTL \"refclk-frequency\"\n"); 89a95cfa6bSAndreas Herrmann goto exit; 90a95cfa6bSAndreas Herrmann } 91a95cfa6bSAndreas Herrmann i = of_property_read_string(uctl_node, 92a95cfa6bSAndreas Herrmann "refclk-type", &clock_type); 93a95cfa6bSAndreas Herrmann 94a95cfa6bSAndreas Herrmann if (!i && strcmp("crystal", clock_type) == 0) 95a95cfa6bSAndreas Herrmann is_crystal_clock = true; 96a95cfa6bSAndreas Herrmann } 97a95cfa6bSAndreas Herrmann 982193dda5SAlan Stern /* 992193dda5SAlan Stern * Step 1: Wait for voltages stable. That surely happened 1002193dda5SAlan Stern * before starting the kernel. 1012193dda5SAlan Stern * 1022193dda5SAlan Stern * Step 2: Enable SCLK of UCTL by writing UCTL0_IF_ENA[EN] = 1 1032193dda5SAlan Stern */ 1042193dda5SAlan Stern if_ena.u64 = 0; 1052193dda5SAlan Stern if_ena.s.en = 1; 1062193dda5SAlan Stern cvmx_write_csr(CVMX_UCTLX_IF_ENA(0), if_ena.u64); 1072193dda5SAlan Stern 1087e78db99SSteven J. Hill for (i = 0; i <= 1; i++) { 1097e78db99SSteven J. Hill port_ctl_status.u64 = 1107e78db99SSteven J. Hill cvmx_read_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0)); 1117e78db99SSteven J. Hill /* Set txvreftune to 15 to obtain compliant 'eye' diagram. */ 1127e78db99SSteven J. Hill port_ctl_status.s.txvreftune = 15; 1137e78db99SSteven J. Hill port_ctl_status.s.txrisetune = 1; 1147e78db99SSteven J. Hill port_ctl_status.s.txpreemphasistune = 1; 1157e78db99SSteven J. Hill cvmx_write_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0), 1167e78db99SSteven J. Hill port_ctl_status.u64); 1177e78db99SSteven J. Hill } 1187e78db99SSteven J. Hill 1192193dda5SAlan Stern /* Step 3: Configure the reference clock, PHY, and HCLK */ 1202193dda5SAlan Stern clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0)); 1212193dda5SAlan Stern 1222193dda5SAlan Stern /* 1232193dda5SAlan Stern * If the UCTL looks like it has already been started, skip 1242193dda5SAlan Stern * the initialization, otherwise bus errors are obtained. 1252193dda5SAlan Stern */ 1262193dda5SAlan Stern if (clk_rst_ctl.s.hrst) 1272193dda5SAlan Stern goto end_clock; 1282193dda5SAlan Stern /* 3a */ 1292193dda5SAlan Stern clk_rst_ctl.s.p_por = 1; 1302193dda5SAlan Stern clk_rst_ctl.s.hrst = 0; 1312193dda5SAlan Stern clk_rst_ctl.s.p_prst = 0; 1322193dda5SAlan Stern clk_rst_ctl.s.h_clkdiv_rst = 0; 1332193dda5SAlan Stern clk_rst_ctl.s.o_clkdiv_rst = 0; 1342193dda5SAlan Stern clk_rst_ctl.s.h_clkdiv_en = 0; 1352193dda5SAlan Stern clk_rst_ctl.s.o_clkdiv_en = 0; 1362193dda5SAlan Stern cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 1372193dda5SAlan Stern 1382193dda5SAlan Stern /* 3b */ 139a95cfa6bSAndreas Herrmann clk_rst_ctl.s.p_refclk_sel = is_crystal_clock ? 0 : 1; 140a95cfa6bSAndreas Herrmann switch (clock_rate) { 141a95cfa6bSAndreas Herrmann default: 142a95cfa6bSAndreas Herrmann pr_err("Invalid UCTL clock rate of %u, using 12000000 instead\n", 143a95cfa6bSAndreas Herrmann clock_rate); 144a95cfa6bSAndreas Herrmann /* Fall through */ 145a95cfa6bSAndreas Herrmann case 12000000: 1462193dda5SAlan Stern clk_rst_ctl.s.p_refclk_div = 0; 147a95cfa6bSAndreas Herrmann break; 148a95cfa6bSAndreas Herrmann case 24000000: 149a95cfa6bSAndreas Herrmann clk_rst_ctl.s.p_refclk_div = 1; 150a95cfa6bSAndreas Herrmann break; 151a95cfa6bSAndreas Herrmann case 48000000: 152a95cfa6bSAndreas Herrmann clk_rst_ctl.s.p_refclk_div = 2; 153a95cfa6bSAndreas Herrmann break; 154a95cfa6bSAndreas Herrmann } 1552193dda5SAlan Stern cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 1562193dda5SAlan Stern 1572193dda5SAlan Stern /* 3c */ 1582193dda5SAlan Stern div = octeon_get_io_clock_rate() / 130000000ull; 1592193dda5SAlan Stern 1602193dda5SAlan Stern switch (div) { 1612193dda5SAlan Stern case 0: 1622193dda5SAlan Stern div = 1; 1632193dda5SAlan Stern break; 1642193dda5SAlan Stern case 1: 1652193dda5SAlan Stern case 2: 1662193dda5SAlan Stern case 3: 1672193dda5SAlan Stern case 4: 1682193dda5SAlan Stern break; 1692193dda5SAlan Stern case 5: 1702193dda5SAlan Stern div = 4; 1712193dda5SAlan Stern break; 1722193dda5SAlan Stern case 6: 1732193dda5SAlan Stern case 7: 1742193dda5SAlan Stern div = 6; 1752193dda5SAlan Stern break; 1762193dda5SAlan Stern case 8: 1772193dda5SAlan Stern case 9: 1782193dda5SAlan Stern case 10: 1792193dda5SAlan Stern case 11: 1802193dda5SAlan Stern div = 8; 1812193dda5SAlan Stern break; 1822193dda5SAlan Stern default: 1832193dda5SAlan Stern div = 12; 1842193dda5SAlan Stern break; 1852193dda5SAlan Stern } 1862193dda5SAlan Stern clk_rst_ctl.s.h_div = div; 1872193dda5SAlan Stern cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 1882193dda5SAlan Stern /* Read it back, */ 1892193dda5SAlan Stern clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0)); 1902193dda5SAlan Stern clk_rst_ctl.s.h_clkdiv_en = 1; 1912193dda5SAlan Stern cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 1922193dda5SAlan Stern /* 3d */ 1932193dda5SAlan Stern clk_rst_ctl.s.h_clkdiv_rst = 1; 1942193dda5SAlan Stern cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 1952193dda5SAlan Stern 1962193dda5SAlan Stern /* 3e: delay 64 io clocks */ 1972193dda5SAlan Stern ndelay(io_clk_64_to_ns); 1982193dda5SAlan Stern 1992193dda5SAlan Stern /* 2002193dda5SAlan Stern * Step 4: Program the power-on reset field in the UCTL 2012193dda5SAlan Stern * clock-reset-control register. 2022193dda5SAlan Stern */ 2032193dda5SAlan Stern clk_rst_ctl.s.p_por = 0; 2042193dda5SAlan Stern cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 2052193dda5SAlan Stern 2067e78db99SSteven J. Hill /* Step 5: Wait 3 ms for the PHY clock to start. */ 2077e78db99SSteven J. Hill mdelay(3); 2082193dda5SAlan Stern 2097e78db99SSteven J. Hill /* Steps 6..9 for ATE only, are skipped. */ 2102193dda5SAlan Stern 2112193dda5SAlan Stern /* Step 10: Configure the OHCI_CLK48 and OHCI_CLK12 clocks. */ 2122193dda5SAlan Stern /* 10a */ 2132193dda5SAlan Stern clk_rst_ctl.s.o_clkdiv_rst = 1; 2142193dda5SAlan Stern cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 2152193dda5SAlan Stern 2162193dda5SAlan Stern /* 10b */ 2172193dda5SAlan Stern clk_rst_ctl.s.o_clkdiv_en = 1; 2182193dda5SAlan Stern cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 2192193dda5SAlan Stern 2202193dda5SAlan Stern /* 10c */ 2212193dda5SAlan Stern ndelay(io_clk_64_to_ns); 2222193dda5SAlan Stern 2232193dda5SAlan Stern /* 2242193dda5SAlan Stern * Step 11: Program the PHY reset field: 2252193dda5SAlan Stern * UCTL0_CLK_RST_CTL[P_PRST] = 1 2262193dda5SAlan Stern */ 2272193dda5SAlan Stern clk_rst_ctl.s.p_prst = 1; 2282193dda5SAlan Stern cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 2292193dda5SAlan Stern 2307e78db99SSteven J. Hill /* Step 11b */ 2317e78db99SSteven J. Hill udelay(1); 2327e78db99SSteven J. Hill 2337e78db99SSteven J. Hill /* Step 11c */ 2347e78db99SSteven J. Hill clk_rst_ctl.s.p_prst = 0; 2357e78db99SSteven J. Hill cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 2367e78db99SSteven J. Hill 2377e78db99SSteven J. Hill /* Step 11d */ 2387e78db99SSteven J. Hill mdelay(1); 2397e78db99SSteven J. Hill 2407e78db99SSteven J. Hill /* Step 11e */ 2417e78db99SSteven J. Hill clk_rst_ctl.s.p_prst = 1; 2427e78db99SSteven J. Hill cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 2437e78db99SSteven J. Hill 2442193dda5SAlan Stern /* Step 12: Wait 1 uS. */ 2452193dda5SAlan Stern udelay(1); 2462193dda5SAlan Stern 2472193dda5SAlan Stern /* Step 13: Program the HRESET_N field: UCTL0_CLK_RST_CTL[HRST] = 1 */ 2482193dda5SAlan Stern clk_rst_ctl.s.hrst = 1; 2492193dda5SAlan Stern cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 2502193dda5SAlan Stern 2512193dda5SAlan Stern end_clock: 2522193dda5SAlan Stern /* Set uSOF cycle period to 60,000 bits. */ 2532193dda5SAlan Stern cvmx_write_csr(CVMX_UCTLX_EHCI_FLA(0), 0x20ull); 2547e78db99SSteven J. Hill 2552193dda5SAlan Stern exit: 2562193dda5SAlan Stern mutex_unlock(&octeon2_usb_clocks_mutex); 2572193dda5SAlan Stern } 2582193dda5SAlan Stern 2592193dda5SAlan Stern static void octeon2_usb_clocks_stop(void) 2602193dda5SAlan Stern { 2612193dda5SAlan Stern mutex_lock(&octeon2_usb_clocks_mutex); 2622193dda5SAlan Stern octeon2_usb_clock_start_cnt--; 2632193dda5SAlan Stern mutex_unlock(&octeon2_usb_clocks_mutex); 2642193dda5SAlan Stern } 2652193dda5SAlan Stern 2662193dda5SAlan Stern static int octeon_ehci_power_on(struct platform_device *pdev) 2672193dda5SAlan Stern { 268a95cfa6bSAndreas Herrmann octeon2_usb_clocks_start(&pdev->dev); 2692193dda5SAlan Stern return 0; 2702193dda5SAlan Stern } 2712193dda5SAlan Stern 2722193dda5SAlan Stern static void octeon_ehci_power_off(struct platform_device *pdev) 2732193dda5SAlan Stern { 2742193dda5SAlan Stern octeon2_usb_clocks_stop(); 2752193dda5SAlan Stern } 2762193dda5SAlan Stern 2772193dda5SAlan Stern static struct usb_ehci_pdata octeon_ehci_pdata = { 2782193dda5SAlan Stern /* Octeon EHCI matches CPU endianness. */ 2792193dda5SAlan Stern #ifdef __BIG_ENDIAN 2802193dda5SAlan Stern .big_endian_mmio = 1, 2812193dda5SAlan Stern #endif 2828552b5b4SSteven J. Hill /* 2838552b5b4SSteven J. Hill * We can DMA from anywhere. But the descriptors must be in 2848552b5b4SSteven J. Hill * the lower 4GB. 2858552b5b4SSteven J. Hill */ 2868552b5b4SSteven J. Hill .dma_mask_64 = 0, 2872193dda5SAlan Stern .power_on = octeon_ehci_power_on, 2882193dda5SAlan Stern .power_off = octeon_ehci_power_off, 2892193dda5SAlan Stern }; 2902193dda5SAlan Stern 291a95cfa6bSAndreas Herrmann static void __init octeon_ehci_hw_start(struct device *dev) 2922193dda5SAlan Stern { 2932193dda5SAlan Stern union cvmx_uctlx_ehci_ctl ehci_ctl; 2942193dda5SAlan Stern 295a95cfa6bSAndreas Herrmann octeon2_usb_clocks_start(dev); 2962193dda5SAlan Stern 2972193dda5SAlan Stern ehci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_EHCI_CTL(0)); 2982193dda5SAlan Stern /* Use 64-bit addressing. */ 2992193dda5SAlan Stern ehci_ctl.s.ehci_64b_addr_en = 1; 3002193dda5SAlan Stern ehci_ctl.s.l2c_addr_msb = 0; 301b0abf36fSPaul Martin #ifdef __BIG_ENDIAN 3022193dda5SAlan Stern ehci_ctl.s.l2c_buff_emod = 1; /* Byte swapped. */ 3032193dda5SAlan Stern ehci_ctl.s.l2c_desc_emod = 1; /* Byte swapped. */ 304b0abf36fSPaul Martin #else 305b0abf36fSPaul Martin ehci_ctl.s.l2c_buff_emod = 0; /* not swapped. */ 306b0abf36fSPaul Martin ehci_ctl.s.l2c_desc_emod = 0; /* not swapped. */ 307b0abf36fSPaul Martin ehci_ctl.s.inv_reg_a2 = 1; 308b0abf36fSPaul Martin #endif 3092193dda5SAlan Stern cvmx_write_csr(CVMX_UCTLX_EHCI_CTL(0), ehci_ctl.u64); 3102193dda5SAlan Stern 3112193dda5SAlan Stern octeon2_usb_clocks_stop(); 3122193dda5SAlan Stern } 3132193dda5SAlan Stern 314340fbb8bSDavid Daney static int __init octeon_ehci_device_init(void) 315340fbb8bSDavid Daney { 316340fbb8bSDavid Daney struct platform_device *pd; 317a95cfa6bSAndreas Herrmann struct device_node *ehci_node; 318340fbb8bSDavid Daney int ret = 0; 319340fbb8bSDavid Daney 320a95cfa6bSAndreas Herrmann ehci_node = of_find_node_by_name(NULL, "ehci"); 321a95cfa6bSAndreas Herrmann if (!ehci_node) 322340fbb8bSDavid Daney return 0; 323340fbb8bSDavid Daney 324a95cfa6bSAndreas Herrmann pd = of_find_device_by_node(ehci_node); 325*b1259519SNicholas Mc Guire of_node_put(ehci_node); 326a95cfa6bSAndreas Herrmann if (!pd) 327a95cfa6bSAndreas Herrmann return 0; 328340fbb8bSDavid Daney 3292193dda5SAlan Stern pd->dev.platform_data = &octeon_ehci_pdata; 330a95cfa6bSAndreas Herrmann octeon_ehci_hw_start(&pd->dev); 3312193dda5SAlan Stern 332340fbb8bSDavid Daney return ret; 333340fbb8bSDavid Daney } 334340fbb8bSDavid Daney device_initcall(octeon_ehci_device_init); 335340fbb8bSDavid Daney 3362193dda5SAlan Stern static int octeon_ohci_power_on(struct platform_device *pdev) 3372193dda5SAlan Stern { 338a95cfa6bSAndreas Herrmann octeon2_usb_clocks_start(&pdev->dev); 3392193dda5SAlan Stern return 0; 3402193dda5SAlan Stern } 3412193dda5SAlan Stern 3422193dda5SAlan Stern static void octeon_ohci_power_off(struct platform_device *pdev) 3432193dda5SAlan Stern { 3442193dda5SAlan Stern octeon2_usb_clocks_stop(); 3452193dda5SAlan Stern } 3462193dda5SAlan Stern 3472193dda5SAlan Stern static struct usb_ohci_pdata octeon_ohci_pdata = { 3482193dda5SAlan Stern /* Octeon OHCI matches CPU endianness. */ 3492193dda5SAlan Stern #ifdef __BIG_ENDIAN 3502193dda5SAlan Stern .big_endian_mmio = 1, 3512193dda5SAlan Stern #endif 3522193dda5SAlan Stern .power_on = octeon_ohci_power_on, 3532193dda5SAlan Stern .power_off = octeon_ohci_power_off, 3542193dda5SAlan Stern }; 3552193dda5SAlan Stern 356a95cfa6bSAndreas Herrmann static void __init octeon_ohci_hw_start(struct device *dev) 3572193dda5SAlan Stern { 3582193dda5SAlan Stern union cvmx_uctlx_ohci_ctl ohci_ctl; 3592193dda5SAlan Stern 360a95cfa6bSAndreas Herrmann octeon2_usb_clocks_start(dev); 3612193dda5SAlan Stern 3622193dda5SAlan Stern ohci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_OHCI_CTL(0)); 3632193dda5SAlan Stern ohci_ctl.s.l2c_addr_msb = 0; 364b0abf36fSPaul Martin #ifdef __BIG_ENDIAN 3652193dda5SAlan Stern ohci_ctl.s.l2c_buff_emod = 1; /* Byte swapped. */ 3662193dda5SAlan Stern ohci_ctl.s.l2c_desc_emod = 1; /* Byte swapped. */ 367b0abf36fSPaul Martin #else 368b0abf36fSPaul Martin ohci_ctl.s.l2c_buff_emod = 0; /* not swapped. */ 369b0abf36fSPaul Martin ohci_ctl.s.l2c_desc_emod = 0; /* not swapped. */ 370b0abf36fSPaul Martin ohci_ctl.s.inv_reg_a2 = 1; 371b0abf36fSPaul Martin #endif 3722193dda5SAlan Stern cvmx_write_csr(CVMX_UCTLX_OHCI_CTL(0), ohci_ctl.u64); 3732193dda5SAlan Stern 3742193dda5SAlan Stern octeon2_usb_clocks_stop(); 3752193dda5SAlan Stern } 3762193dda5SAlan Stern 377340fbb8bSDavid Daney static int __init octeon_ohci_device_init(void) 378340fbb8bSDavid Daney { 379340fbb8bSDavid Daney struct platform_device *pd; 380a95cfa6bSAndreas Herrmann struct device_node *ohci_node; 381340fbb8bSDavid Daney int ret = 0; 382340fbb8bSDavid Daney 383a95cfa6bSAndreas Herrmann ohci_node = of_find_node_by_name(NULL, "ohci"); 384a95cfa6bSAndreas Herrmann if (!ohci_node) 385340fbb8bSDavid Daney return 0; 386340fbb8bSDavid Daney 387a95cfa6bSAndreas Herrmann pd = of_find_device_by_node(ohci_node); 388*b1259519SNicholas Mc Guire of_node_put(ohci_node); 389a95cfa6bSAndreas Herrmann if (!pd) 390a95cfa6bSAndreas Herrmann return 0; 391340fbb8bSDavid Daney 3922193dda5SAlan Stern pd->dev.platform_data = &octeon_ohci_pdata; 393a95cfa6bSAndreas Herrmann octeon_ohci_hw_start(&pd->dev); 3942193dda5SAlan Stern 395340fbb8bSDavid Daney return ret; 396340fbb8bSDavid Daney } 397340fbb8bSDavid Daney device_initcall(octeon_ohci_device_init); 398340fbb8bSDavid Daney 399340fbb8bSDavid Daney #endif /* CONFIG_USB */ 400340fbb8bSDavid Daney 4017fd57ab9SSteven J. Hill /* Octeon Random Number Generator. */ 4027fd57ab9SSteven J. Hill static int __init octeon_rng_device_init(void) 4037fd57ab9SSteven J. Hill { 4047fd57ab9SSteven J. Hill struct platform_device *pd; 4057fd57ab9SSteven J. Hill int ret = 0; 4067fd57ab9SSteven J. Hill 4077fd57ab9SSteven J. Hill struct resource rng_resources[] = { 4087fd57ab9SSteven J. Hill { 4097fd57ab9SSteven J. Hill .flags = IORESOURCE_MEM, 4107fd57ab9SSteven J. Hill .start = XKPHYS_TO_PHYS(CVMX_RNM_CTL_STATUS), 4117fd57ab9SSteven J. Hill .end = XKPHYS_TO_PHYS(CVMX_RNM_CTL_STATUS) + 0xf 4127fd57ab9SSteven J. Hill }, { 4137fd57ab9SSteven J. Hill .flags = IORESOURCE_MEM, 4147fd57ab9SSteven J. Hill .start = cvmx_build_io_address(8, 0), 4157fd57ab9SSteven J. Hill .end = cvmx_build_io_address(8, 0) + 0x7 4167fd57ab9SSteven J. Hill } 4177fd57ab9SSteven J. Hill }; 4187fd57ab9SSteven J. Hill 4197fd57ab9SSteven J. Hill pd = platform_device_alloc("octeon_rng", -1); 4207fd57ab9SSteven J. Hill if (!pd) { 4217fd57ab9SSteven J. Hill ret = -ENOMEM; 4227fd57ab9SSteven J. Hill goto out; 4237fd57ab9SSteven J. Hill } 4247fd57ab9SSteven J. Hill 4257fd57ab9SSteven J. Hill ret = platform_device_add_resources(pd, rng_resources, 4267fd57ab9SSteven J. Hill ARRAY_SIZE(rng_resources)); 4277fd57ab9SSteven J. Hill if (ret) 4287fd57ab9SSteven J. Hill goto fail; 4297fd57ab9SSteven J. Hill 4307fd57ab9SSteven J. Hill ret = platform_device_add(pd); 4317fd57ab9SSteven J. Hill if (ret) 4327fd57ab9SSteven J. Hill goto fail; 4337fd57ab9SSteven J. Hill 4347fd57ab9SSteven J. Hill return ret; 4357fd57ab9SSteven J. Hill fail: 4367fd57ab9SSteven J. Hill platform_device_put(pd); 4377fd57ab9SSteven J. Hill 4387fd57ab9SSteven J. Hill out: 4397fd57ab9SSteven J. Hill return ret; 4407fd57ab9SSteven J. Hill } 4417fd57ab9SSteven J. Hill device_initcall(octeon_rng_device_init); 442a95cfa6bSAndreas Herrmann 443e96b1b06SSteven J. Hill const struct of_device_id octeon_ids[] __initconst = { 4447ed18152SDavid Daney { .compatible = "simple-bus", }, 4457ed18152SDavid Daney { .compatible = "cavium,octeon-6335-uctl", }, 446d617f9e9SDavid Daney { .compatible = "cavium,octeon-5750-usbn", }, 4477ed18152SDavid Daney { .compatible = "cavium,octeon-3860-bootbus", }, 4487ed18152SDavid Daney { .compatible = "cavium,mdio-mux", }, 4497ed18152SDavid Daney { .compatible = "gpio-leds", }, 45093e502b3SSteven J. Hill { .compatible = "cavium,octeon-7130-usb-uctl", }, 4517ed18152SDavid Daney {}, 4527ed18152SDavid Daney }; 4537ed18152SDavid Daney 4547ed18152SDavid Daney static bool __init octeon_has_88e1145(void) 4557ed18152SDavid Daney { 4567ed18152SDavid Daney return !OCTEON_IS_MODEL(OCTEON_CN52XX) && 4577ed18152SDavid Daney !OCTEON_IS_MODEL(OCTEON_CN6XXX) && 4587ed18152SDavid Daney !OCTEON_IS_MODEL(OCTEON_CN56XX); 4597ed18152SDavid Daney } 4607ed18152SDavid Daney 4617ed18152SDavid Daney static void __init octeon_fdt_set_phy(int eth, int phy_addr) 4627ed18152SDavid Daney { 4637ed18152SDavid Daney const __be32 *phy_handle; 4647ed18152SDavid Daney const __be32 *alt_phy_handle; 4657ed18152SDavid Daney const __be32 *reg; 4667ed18152SDavid Daney u32 phandle; 4677ed18152SDavid Daney int phy; 4687ed18152SDavid Daney int alt_phy; 4697ed18152SDavid Daney const char *p; 4707ed18152SDavid Daney int current_len; 4717ed18152SDavid Daney char new_name[20]; 4727ed18152SDavid Daney 4737ed18152SDavid Daney phy_handle = fdt_getprop(initial_boot_params, eth, "phy-handle", NULL); 4747ed18152SDavid Daney if (!phy_handle) 4757ed18152SDavid Daney return; 4767ed18152SDavid Daney 4777ed18152SDavid Daney phandle = be32_to_cpup(phy_handle); 4787ed18152SDavid Daney phy = fdt_node_offset_by_phandle(initial_boot_params, phandle); 4797ed18152SDavid Daney 4807ed18152SDavid Daney alt_phy_handle = fdt_getprop(initial_boot_params, eth, "cavium,alt-phy-handle", NULL); 4817ed18152SDavid Daney if (alt_phy_handle) { 4827ed18152SDavid Daney u32 alt_phandle = be32_to_cpup(alt_phy_handle); 483e96b1b06SSteven J. Hill 4847ed18152SDavid Daney alt_phy = fdt_node_offset_by_phandle(initial_boot_params, alt_phandle); 4857ed18152SDavid Daney } else { 4867ed18152SDavid Daney alt_phy = -1; 4877ed18152SDavid Daney } 4887ed18152SDavid Daney 4897ed18152SDavid Daney if (phy_addr < 0 || phy < 0) { 4907ed18152SDavid Daney /* Delete the PHY things */ 4917ed18152SDavid Daney fdt_nop_property(initial_boot_params, eth, "phy-handle"); 4927ed18152SDavid Daney /* This one may fail */ 4937ed18152SDavid Daney fdt_nop_property(initial_boot_params, eth, "cavium,alt-phy-handle"); 4947ed18152SDavid Daney if (phy >= 0) 4957ed18152SDavid Daney fdt_nop_node(initial_boot_params, phy); 4967ed18152SDavid Daney if (alt_phy >= 0) 4977ed18152SDavid Daney fdt_nop_node(initial_boot_params, alt_phy); 4987ed18152SDavid Daney return; 4997ed18152SDavid Daney } 5007ed18152SDavid Daney 5017ed18152SDavid Daney if (phy_addr >= 256 && alt_phy > 0) { 5027ed18152SDavid Daney const struct fdt_property *phy_prop; 5037ed18152SDavid Daney struct fdt_property *alt_prop; 5047ed18152SDavid Daney u32 phy_handle_name; 5057ed18152SDavid Daney 5067ed18152SDavid Daney /* Use the alt phy node instead.*/ 5077ed18152SDavid Daney phy_prop = fdt_get_property(initial_boot_params, eth, "phy-handle", NULL); 5087ed18152SDavid Daney phy_handle_name = phy_prop->nameoff; 5097ed18152SDavid Daney fdt_nop_node(initial_boot_params, phy); 5107ed18152SDavid Daney fdt_nop_property(initial_boot_params, eth, "phy-handle"); 5117ed18152SDavid Daney alt_prop = fdt_get_property_w(initial_boot_params, eth, "cavium,alt-phy-handle", NULL); 5127ed18152SDavid Daney alt_prop->nameoff = phy_handle_name; 5137ed18152SDavid Daney phy = alt_phy; 5147ed18152SDavid Daney } 5157ed18152SDavid Daney 5167ed18152SDavid Daney phy_addr &= 0xff; 5177ed18152SDavid Daney 5187ed18152SDavid Daney if (octeon_has_88e1145()) { 5197ed18152SDavid Daney fdt_nop_property(initial_boot_params, phy, "marvell,reg-init"); 5207ed18152SDavid Daney memset(new_name, 0, sizeof(new_name)); 5217ed18152SDavid Daney strcpy(new_name, "marvell,88e1145"); 5227ed18152SDavid Daney p = fdt_getprop(initial_boot_params, phy, "compatible", 5237ed18152SDavid Daney ¤t_len); 5247ed18152SDavid Daney if (p && current_len >= strlen(new_name)) 5257ed18152SDavid Daney fdt_setprop_inplace(initial_boot_params, phy, 5267ed18152SDavid Daney "compatible", new_name, current_len); 5277ed18152SDavid Daney } 5287ed18152SDavid Daney 5297ed18152SDavid Daney reg = fdt_getprop(initial_boot_params, phy, "reg", NULL); 5307ed18152SDavid Daney if (phy_addr == be32_to_cpup(reg)) 5317ed18152SDavid Daney return; 5327ed18152SDavid Daney 5337ed18152SDavid Daney fdt_setprop_inplace_cell(initial_boot_params, phy, "reg", phy_addr); 5347ed18152SDavid Daney 5357ed18152SDavid Daney snprintf(new_name, sizeof(new_name), "ethernet-phy@%x", phy_addr); 5367ed18152SDavid Daney 5377ed18152SDavid Daney p = fdt_get_name(initial_boot_params, phy, ¤t_len); 5387ed18152SDavid Daney if (p && current_len == strlen(new_name)) 5397ed18152SDavid Daney fdt_set_name(initial_boot_params, phy, new_name); 5407ed18152SDavid Daney else 5417ed18152SDavid Daney pr_err("Error: could not rename ethernet phy: <%s>", p); 5427ed18152SDavid Daney } 5437ed18152SDavid Daney 5447ed18152SDavid Daney static void __init octeon_fdt_set_mac_addr(int n, u64 *pmac) 5457ed18152SDavid Daney { 546377de399SAaro Koskinen const u8 *old_mac; 547377de399SAaro Koskinen int old_len; 5487ed18152SDavid Daney u8 new_mac[6]; 5497ed18152SDavid Daney u64 mac = *pmac; 5507ed18152SDavid Daney int r; 5517ed18152SDavid Daney 552377de399SAaro Koskinen old_mac = fdt_getprop(initial_boot_params, n, "local-mac-address", 553377de399SAaro Koskinen &old_len); 554377de399SAaro Koskinen if (!old_mac || old_len != 6 || is_valid_ether_addr(old_mac)) 555377de399SAaro Koskinen return; 556377de399SAaro Koskinen 5577ed18152SDavid Daney new_mac[0] = (mac >> 40) & 0xff; 5587ed18152SDavid Daney new_mac[1] = (mac >> 32) & 0xff; 5597ed18152SDavid Daney new_mac[2] = (mac >> 24) & 0xff; 5607ed18152SDavid Daney new_mac[3] = (mac >> 16) & 0xff; 5617ed18152SDavid Daney new_mac[4] = (mac >> 8) & 0xff; 5627ed18152SDavid Daney new_mac[5] = mac & 0xff; 5637ed18152SDavid Daney 5647ed18152SDavid Daney r = fdt_setprop_inplace(initial_boot_params, n, "local-mac-address", 5657ed18152SDavid Daney new_mac, sizeof(new_mac)); 5667ed18152SDavid Daney 5677ed18152SDavid Daney if (r) { 5687ed18152SDavid Daney pr_err("Setting \"local-mac-address\" failed %d", r); 5697ed18152SDavid Daney return; 5707ed18152SDavid Daney } 5717ed18152SDavid Daney *pmac = mac + 1; 5727ed18152SDavid Daney } 5737ed18152SDavid Daney 5747ed18152SDavid Daney static void __init octeon_fdt_rm_ethernet(int node) 5757ed18152SDavid Daney { 5767ed18152SDavid Daney const __be32 *phy_handle; 5777ed18152SDavid Daney 5787ed18152SDavid Daney phy_handle = fdt_getprop(initial_boot_params, node, "phy-handle", NULL); 5797ed18152SDavid Daney if (phy_handle) { 5807ed18152SDavid Daney u32 ph = be32_to_cpup(phy_handle); 5817ed18152SDavid Daney int p = fdt_node_offset_by_phandle(initial_boot_params, ph); 582e96b1b06SSteven J. Hill 5837ed18152SDavid Daney if (p >= 0) 5847ed18152SDavid Daney fdt_nop_node(initial_boot_params, p); 5857ed18152SDavid Daney } 5867ed18152SDavid Daney fdt_nop_node(initial_boot_params, node); 5877ed18152SDavid Daney } 5887ed18152SDavid Daney 58943349b9eSAaro Koskinen static void __init octeon_fdt_pip_port(int iface, int i, int p, int max) 5907ed18152SDavid Daney { 5917ed18152SDavid Daney char name_buffer[20]; 5927ed18152SDavid Daney int eth; 5937ed18152SDavid Daney int phy_addr; 5947ed18152SDavid Daney int ipd_port; 5957ed18152SDavid Daney 5967ed18152SDavid Daney snprintf(name_buffer, sizeof(name_buffer), "ethernet@%x", p); 5977ed18152SDavid Daney eth = fdt_subnode_offset(initial_boot_params, iface, name_buffer); 5987ed18152SDavid Daney if (eth < 0) 5997ed18152SDavid Daney return; 6007ed18152SDavid Daney if (p > max) { 6017ed18152SDavid Daney pr_debug("Deleting port %x:%x\n", i, p); 6027ed18152SDavid Daney octeon_fdt_rm_ethernet(eth); 6037ed18152SDavid Daney return; 6047ed18152SDavid Daney } 6057ed18152SDavid Daney if (OCTEON_IS_MODEL(OCTEON_CN68XX)) 6067ed18152SDavid Daney ipd_port = (0x100 * i) + (0x10 * p) + 0x800; 6077ed18152SDavid Daney else 6087ed18152SDavid Daney ipd_port = 16 * i + p; 6097ed18152SDavid Daney 6107ed18152SDavid Daney phy_addr = cvmx_helper_board_get_mii_address(ipd_port); 6117ed18152SDavid Daney octeon_fdt_set_phy(eth, phy_addr); 6127ed18152SDavid Daney } 6137ed18152SDavid Daney 61443349b9eSAaro Koskinen static void __init octeon_fdt_pip_iface(int pip, int idx) 6157ed18152SDavid Daney { 6167ed18152SDavid Daney char name_buffer[20]; 6177ed18152SDavid Daney int iface; 6187ed18152SDavid Daney int p; 619ab2bb148SFaidon Liambotis int count = 0; 6207ed18152SDavid Daney 6217ed18152SDavid Daney snprintf(name_buffer, sizeof(name_buffer), "interface@%d", idx); 6227ed18152SDavid Daney iface = fdt_subnode_offset(initial_boot_params, pip, name_buffer); 6237ed18152SDavid Daney if (iface < 0) 6247ed18152SDavid Daney return; 6257ed18152SDavid Daney 626b2e4f156SAaro Koskinen if (cvmx_helper_interface_enumerate(idx) == 0) 627b2e4f156SAaro Koskinen count = cvmx_helper_ports_on_interface(idx); 628b2e4f156SAaro Koskinen 6297ed18152SDavid Daney for (p = 0; p < 16; p++) 63043349b9eSAaro Koskinen octeon_fdt_pip_port(iface, idx, p, count - 1); 63143349b9eSAaro Koskinen } 63243349b9eSAaro Koskinen 63343349b9eSAaro Koskinen void __init octeon_fill_mac_addresses(void) 63443349b9eSAaro Koskinen { 63543349b9eSAaro Koskinen const char *alias_prop; 63643349b9eSAaro Koskinen char name_buffer[20]; 63743349b9eSAaro Koskinen u64 mac_addr_base; 63843349b9eSAaro Koskinen int aliases; 63943349b9eSAaro Koskinen int pip; 64043349b9eSAaro Koskinen int i; 64143349b9eSAaro Koskinen 64243349b9eSAaro Koskinen aliases = fdt_path_offset(initial_boot_params, "/aliases"); 64343349b9eSAaro Koskinen if (aliases < 0) 64443349b9eSAaro Koskinen return; 64543349b9eSAaro Koskinen 64643349b9eSAaro Koskinen mac_addr_base = 64743349b9eSAaro Koskinen ((octeon_bootinfo->mac_addr_base[0] & 0xffull)) << 40 | 64843349b9eSAaro Koskinen ((octeon_bootinfo->mac_addr_base[1] & 0xffull)) << 32 | 64943349b9eSAaro Koskinen ((octeon_bootinfo->mac_addr_base[2] & 0xffull)) << 24 | 65043349b9eSAaro Koskinen ((octeon_bootinfo->mac_addr_base[3] & 0xffull)) << 16 | 65143349b9eSAaro Koskinen ((octeon_bootinfo->mac_addr_base[4] & 0xffull)) << 8 | 65243349b9eSAaro Koskinen (octeon_bootinfo->mac_addr_base[5] & 0xffull); 65343349b9eSAaro Koskinen 65443349b9eSAaro Koskinen for (i = 0; i < 2; i++) { 65543349b9eSAaro Koskinen int mgmt; 65643349b9eSAaro Koskinen 65743349b9eSAaro Koskinen snprintf(name_buffer, sizeof(name_buffer), "mix%d", i); 65843349b9eSAaro Koskinen alias_prop = fdt_getprop(initial_boot_params, aliases, 65943349b9eSAaro Koskinen name_buffer, NULL); 66043349b9eSAaro Koskinen if (!alias_prop) 66143349b9eSAaro Koskinen continue; 66243349b9eSAaro Koskinen mgmt = fdt_path_offset(initial_boot_params, alias_prop); 66343349b9eSAaro Koskinen if (mgmt < 0) 66443349b9eSAaro Koskinen continue; 66543349b9eSAaro Koskinen octeon_fdt_set_mac_addr(mgmt, &mac_addr_base); 66643349b9eSAaro Koskinen } 66743349b9eSAaro Koskinen 66843349b9eSAaro Koskinen alias_prop = fdt_getprop(initial_boot_params, aliases, "pip", NULL); 66943349b9eSAaro Koskinen if (!alias_prop) 67043349b9eSAaro Koskinen return; 67143349b9eSAaro Koskinen 67243349b9eSAaro Koskinen pip = fdt_path_offset(initial_boot_params, alias_prop); 67343349b9eSAaro Koskinen if (pip < 0) 67443349b9eSAaro Koskinen return; 67543349b9eSAaro Koskinen 67643349b9eSAaro Koskinen for (i = 0; i <= 4; i++) { 67743349b9eSAaro Koskinen int iface; 67843349b9eSAaro Koskinen int p; 67943349b9eSAaro Koskinen 68043349b9eSAaro Koskinen snprintf(name_buffer, sizeof(name_buffer), "interface@%d", i); 68143349b9eSAaro Koskinen iface = fdt_subnode_offset(initial_boot_params, pip, 68243349b9eSAaro Koskinen name_buffer); 68343349b9eSAaro Koskinen if (iface < 0) 68443349b9eSAaro Koskinen continue; 68543349b9eSAaro Koskinen for (p = 0; p < 16; p++) { 68643349b9eSAaro Koskinen int eth; 68743349b9eSAaro Koskinen 68843349b9eSAaro Koskinen snprintf(name_buffer, sizeof(name_buffer), 68943349b9eSAaro Koskinen "ethernet@%x", p); 69043349b9eSAaro Koskinen eth = fdt_subnode_offset(initial_boot_params, iface, 69143349b9eSAaro Koskinen name_buffer); 69243349b9eSAaro Koskinen if (eth < 0) 69343349b9eSAaro Koskinen continue; 69443349b9eSAaro Koskinen octeon_fdt_set_mac_addr(eth, &mac_addr_base); 69543349b9eSAaro Koskinen } 69643349b9eSAaro Koskinen } 6977ed18152SDavid Daney } 6987ed18152SDavid Daney 6997ed18152SDavid Daney int __init octeon_prune_device_tree(void) 7007ed18152SDavid Daney { 7017ed18152SDavid Daney int i, max_port, uart_mask; 7027ed18152SDavid Daney const char *pip_path; 7037ed18152SDavid Daney const char *alias_prop; 7047ed18152SDavid Daney char name_buffer[20]; 7057ed18152SDavid Daney int aliases; 7067ed18152SDavid Daney 7077ed18152SDavid Daney if (fdt_check_header(initial_boot_params)) 7087ed18152SDavid Daney panic("Corrupt Device Tree."); 7097ed18152SDavid Daney 71086bee12fSAaro Koskinen WARN(octeon_bootinfo->board_type == CVMX_BOARD_TYPE_CUST_DSR1000N, 71186bee12fSAaro Koskinen "Built-in DTB booting is deprecated on %s. Please switch to use appended DTB.", 71286bee12fSAaro Koskinen cvmx_board_type_to_string(octeon_bootinfo->board_type)); 71386bee12fSAaro Koskinen 7147ed18152SDavid Daney aliases = fdt_path_offset(initial_boot_params, "/aliases"); 7157ed18152SDavid Daney if (aliases < 0) { 7167ed18152SDavid Daney pr_err("Error: No /aliases node in device tree."); 7177ed18152SDavid Daney return -EINVAL; 7187ed18152SDavid Daney } 7197ed18152SDavid Daney 7207ed18152SDavid Daney if (OCTEON_IS_MODEL(OCTEON_CN52XX) || OCTEON_IS_MODEL(OCTEON_CN63XX)) 7217ed18152SDavid Daney max_port = 2; 7227ed18152SDavid Daney else if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN68XX)) 7237ed18152SDavid Daney max_port = 1; 7247ed18152SDavid Daney else 7257ed18152SDavid Daney max_port = 0; 7267ed18152SDavid Daney 7277ed18152SDavid Daney if (octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC10E) 7287ed18152SDavid Daney max_port = 0; 7297ed18152SDavid Daney 7307ed18152SDavid Daney for (i = 0; i < 2; i++) { 7317ed18152SDavid Daney int mgmt; 732e96b1b06SSteven J. Hill 7337ed18152SDavid Daney snprintf(name_buffer, sizeof(name_buffer), 7347ed18152SDavid Daney "mix%d", i); 7357ed18152SDavid Daney alias_prop = fdt_getprop(initial_boot_params, aliases, 7367ed18152SDavid Daney name_buffer, NULL); 7377ed18152SDavid Daney if (alias_prop) { 7387ed18152SDavid Daney mgmt = fdt_path_offset(initial_boot_params, alias_prop); 7397ed18152SDavid Daney if (mgmt < 0) 7407ed18152SDavid Daney continue; 7417ed18152SDavid Daney if (i >= max_port) { 7427ed18152SDavid Daney pr_debug("Deleting mix%d\n", i); 7437ed18152SDavid Daney octeon_fdt_rm_ethernet(mgmt); 7447ed18152SDavid Daney fdt_nop_property(initial_boot_params, aliases, 7457ed18152SDavid Daney name_buffer); 7467ed18152SDavid Daney } else { 7477ed18152SDavid Daney int phy_addr = cvmx_helper_board_get_mii_address(CVMX_HELPER_BOARD_MGMT_IPD_PORT + i); 748e96b1b06SSteven J. Hill 7497ed18152SDavid Daney octeon_fdt_set_phy(mgmt, phy_addr); 7507ed18152SDavid Daney } 7517ed18152SDavid Daney } 7527ed18152SDavid Daney } 7537ed18152SDavid Daney 7547ed18152SDavid Daney pip_path = fdt_getprop(initial_boot_params, aliases, "pip", NULL); 7557ed18152SDavid Daney if (pip_path) { 7567ed18152SDavid Daney int pip = fdt_path_offset(initial_boot_params, pip_path); 757e96b1b06SSteven J. Hill 7587ed18152SDavid Daney if (pip >= 0) 7597ed18152SDavid Daney for (i = 0; i <= 4; i++) 76043349b9eSAaro Koskinen octeon_fdt_pip_iface(pip, i); 7617ed18152SDavid Daney } 7627ed18152SDavid Daney 7637ed18152SDavid Daney /* I2C */ 7647ed18152SDavid Daney if (OCTEON_IS_MODEL(OCTEON_CN52XX) || 7657ed18152SDavid Daney OCTEON_IS_MODEL(OCTEON_CN63XX) || 7667ed18152SDavid Daney OCTEON_IS_MODEL(OCTEON_CN68XX) || 7677ed18152SDavid Daney OCTEON_IS_MODEL(OCTEON_CN56XX)) 7687ed18152SDavid Daney max_port = 2; 7697ed18152SDavid Daney else 7707ed18152SDavid Daney max_port = 1; 7717ed18152SDavid Daney 7727ed18152SDavid Daney for (i = 0; i < 2; i++) { 7737ed18152SDavid Daney int i2c; 774e96b1b06SSteven J. Hill 7757ed18152SDavid Daney snprintf(name_buffer, sizeof(name_buffer), 7767ed18152SDavid Daney "twsi%d", i); 7777ed18152SDavid Daney alias_prop = fdt_getprop(initial_boot_params, aliases, 7787ed18152SDavid Daney name_buffer, NULL); 7797ed18152SDavid Daney 7807ed18152SDavid Daney if (alias_prop) { 7817ed18152SDavid Daney i2c = fdt_path_offset(initial_boot_params, alias_prop); 7827ed18152SDavid Daney if (i2c < 0) 7837ed18152SDavid Daney continue; 7847ed18152SDavid Daney if (i >= max_port) { 7857ed18152SDavid Daney pr_debug("Deleting twsi%d\n", i); 7867ed18152SDavid Daney fdt_nop_node(initial_boot_params, i2c); 7877ed18152SDavid Daney fdt_nop_property(initial_boot_params, aliases, 7887ed18152SDavid Daney name_buffer); 7897ed18152SDavid Daney } 7907ed18152SDavid Daney } 7917ed18152SDavid Daney } 7927ed18152SDavid Daney 7937ed18152SDavid Daney /* SMI/MDIO */ 7947ed18152SDavid Daney if (OCTEON_IS_MODEL(OCTEON_CN68XX)) 7957ed18152SDavid Daney max_port = 4; 7967ed18152SDavid Daney else if (OCTEON_IS_MODEL(OCTEON_CN52XX) || 7977ed18152SDavid Daney OCTEON_IS_MODEL(OCTEON_CN63XX) || 7987ed18152SDavid Daney OCTEON_IS_MODEL(OCTEON_CN56XX)) 7997ed18152SDavid Daney max_port = 2; 8007ed18152SDavid Daney else 8017ed18152SDavid Daney max_port = 1; 8027ed18152SDavid Daney 8037ed18152SDavid Daney for (i = 0; i < 2; i++) { 8047ed18152SDavid Daney int i2c; 805e96b1b06SSteven J. Hill 8067ed18152SDavid Daney snprintf(name_buffer, sizeof(name_buffer), 8077ed18152SDavid Daney "smi%d", i); 8087ed18152SDavid Daney alias_prop = fdt_getprop(initial_boot_params, aliases, 8097ed18152SDavid Daney name_buffer, NULL); 8107ed18152SDavid Daney if (alias_prop) { 8117ed18152SDavid Daney i2c = fdt_path_offset(initial_boot_params, alias_prop); 8127ed18152SDavid Daney if (i2c < 0) 8137ed18152SDavid Daney continue; 8147ed18152SDavid Daney if (i >= max_port) { 8157ed18152SDavid Daney pr_debug("Deleting smi%d\n", i); 8167ed18152SDavid Daney fdt_nop_node(initial_boot_params, i2c); 8177ed18152SDavid Daney fdt_nop_property(initial_boot_params, aliases, 8187ed18152SDavid Daney name_buffer); 8197ed18152SDavid Daney } 8207ed18152SDavid Daney } 8217ed18152SDavid Daney } 8227ed18152SDavid Daney 8237ed18152SDavid Daney /* Serial */ 8247ed18152SDavid Daney uart_mask = 3; 8257ed18152SDavid Daney 8267ed18152SDavid Daney /* Right now CN52XX is the only chip with a third uart */ 8277ed18152SDavid Daney if (OCTEON_IS_MODEL(OCTEON_CN52XX)) 8287ed18152SDavid Daney uart_mask |= 4; /* uart2 */ 8297ed18152SDavid Daney 8307ed18152SDavid Daney for (i = 0; i < 3; i++) { 8317ed18152SDavid Daney int uart; 832e96b1b06SSteven J. Hill 8337ed18152SDavid Daney snprintf(name_buffer, sizeof(name_buffer), 8347ed18152SDavid Daney "uart%d", i); 8357ed18152SDavid Daney alias_prop = fdt_getprop(initial_boot_params, aliases, 8367ed18152SDavid Daney name_buffer, NULL); 8377ed18152SDavid Daney 8387ed18152SDavid Daney if (alias_prop) { 8397ed18152SDavid Daney uart = fdt_path_offset(initial_boot_params, alias_prop); 8405219343fSDavid Daney if (uart_mask & (1 << i)) { 8415219343fSDavid Daney __be32 f; 8425219343fSDavid Daney 8435219343fSDavid Daney f = cpu_to_be32(octeon_get_io_clock_rate()); 8445219343fSDavid Daney fdt_setprop_inplace(initial_boot_params, 8455219343fSDavid Daney uart, "clock-frequency", 8465219343fSDavid Daney &f, sizeof(f)); 8477ed18152SDavid Daney continue; 8485219343fSDavid Daney } 8497ed18152SDavid Daney pr_debug("Deleting uart%d\n", i); 8507ed18152SDavid Daney fdt_nop_node(initial_boot_params, uart); 8517ed18152SDavid Daney fdt_nop_property(initial_boot_params, aliases, 8527ed18152SDavid Daney name_buffer); 8537ed18152SDavid Daney } 8547ed18152SDavid Daney } 8557ed18152SDavid Daney 8567ed18152SDavid Daney /* Compact Flash */ 8577ed18152SDavid Daney alias_prop = fdt_getprop(initial_boot_params, aliases, 8587ed18152SDavid Daney "cf0", NULL); 8597ed18152SDavid Daney if (alias_prop) { 8607ed18152SDavid Daney union cvmx_mio_boot_reg_cfgx mio_boot_reg_cfg; 8617ed18152SDavid Daney unsigned long base_ptr, region_base, region_size; 8627ed18152SDavid Daney unsigned long region1_base = 0; 8637ed18152SDavid Daney unsigned long region1_size = 0; 8647ed18152SDavid Daney int cs, bootbus; 8657ed18152SDavid Daney bool is_16bit = false; 8667ed18152SDavid Daney bool is_true_ide = false; 8677ed18152SDavid Daney __be32 new_reg[6]; 8687ed18152SDavid Daney __be32 *ranges; 8697ed18152SDavid Daney int len; 8707ed18152SDavid Daney 8717ed18152SDavid Daney int cf = fdt_path_offset(initial_boot_params, alias_prop); 872e96b1b06SSteven J. Hill 8737ed18152SDavid Daney base_ptr = 0; 8747ed18152SDavid Daney if (octeon_bootinfo->major_version == 1 8757ed18152SDavid Daney && octeon_bootinfo->minor_version >= 1) { 8767ed18152SDavid Daney if (octeon_bootinfo->compact_flash_common_base_addr) 8777ed18152SDavid Daney base_ptr = octeon_bootinfo->compact_flash_common_base_addr; 8787ed18152SDavid Daney } else { 8797ed18152SDavid Daney base_ptr = 0x1d000800; 8807ed18152SDavid Daney } 8817ed18152SDavid Daney 8827ed18152SDavid Daney if (!base_ptr) 8837ed18152SDavid Daney goto no_cf; 8847ed18152SDavid Daney 8857ed18152SDavid Daney /* Find CS0 region. */ 8867ed18152SDavid Daney for (cs = 0; cs < 8; cs++) { 8877ed18152SDavid Daney mio_boot_reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs)); 8887ed18152SDavid Daney region_base = mio_boot_reg_cfg.s.base << 16; 8897ed18152SDavid Daney region_size = (mio_boot_reg_cfg.s.size + 1) << 16; 8907ed18152SDavid Daney if (mio_boot_reg_cfg.s.en && base_ptr >= region_base 8917ed18152SDavid Daney && base_ptr < region_base + region_size) { 8927ed18152SDavid Daney is_16bit = mio_boot_reg_cfg.s.width; 8937ed18152SDavid Daney break; 8947ed18152SDavid Daney } 8957ed18152SDavid Daney } 8967ed18152SDavid Daney if (cs >= 7) { 8977ed18152SDavid Daney /* cs and cs + 1 are CS0 and CS1, both must be less than 8. */ 8987ed18152SDavid Daney goto no_cf; 8997ed18152SDavid Daney } 9007ed18152SDavid Daney 9017ed18152SDavid Daney if (!(base_ptr & 0xfffful)) { 9027ed18152SDavid Daney /* 9037ed18152SDavid Daney * Boot loader signals availability of DMA (true_ide 9047ed18152SDavid Daney * mode) by setting low order bits of base_ptr to 9057ed18152SDavid Daney * zero. 9067ed18152SDavid Daney */ 9077ed18152SDavid Daney 9087ed18152SDavid Daney /* Asume that CS1 immediately follows. */ 9097ed18152SDavid Daney mio_boot_reg_cfg.u64 = 9107ed18152SDavid Daney cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs + 1)); 9117ed18152SDavid Daney region1_base = mio_boot_reg_cfg.s.base << 16; 9127ed18152SDavid Daney region1_size = (mio_boot_reg_cfg.s.size + 1) << 16; 9137ed18152SDavid Daney if (!mio_boot_reg_cfg.s.en) 9147ed18152SDavid Daney goto no_cf; 9157ed18152SDavid Daney is_true_ide = true; 9167ed18152SDavid Daney 9177ed18152SDavid Daney } else { 9187ed18152SDavid Daney fdt_nop_property(initial_boot_params, cf, "cavium,true-ide"); 9197ed18152SDavid Daney fdt_nop_property(initial_boot_params, cf, "cavium,dma-engine-handle"); 9207ed18152SDavid Daney if (!is_16bit) { 9217ed18152SDavid Daney __be32 width = cpu_to_be32(8); 922e96b1b06SSteven J. Hill 9237ed18152SDavid Daney fdt_setprop_inplace(initial_boot_params, cf, 9247ed18152SDavid Daney "cavium,bus-width", &width, sizeof(width)); 9257ed18152SDavid Daney } 9267ed18152SDavid Daney } 9277ed18152SDavid Daney new_reg[0] = cpu_to_be32(cs); 9287ed18152SDavid Daney new_reg[1] = cpu_to_be32(0); 9297ed18152SDavid Daney new_reg[2] = cpu_to_be32(0x10000); 9307ed18152SDavid Daney new_reg[3] = cpu_to_be32(cs + 1); 9317ed18152SDavid Daney new_reg[4] = cpu_to_be32(0); 9327ed18152SDavid Daney new_reg[5] = cpu_to_be32(0x10000); 9337ed18152SDavid Daney fdt_setprop_inplace(initial_boot_params, cf, 9347ed18152SDavid Daney "reg", new_reg, sizeof(new_reg)); 9357ed18152SDavid Daney 9367ed18152SDavid Daney bootbus = fdt_parent_offset(initial_boot_params, cf); 9377ed18152SDavid Daney if (bootbus < 0) 9387ed18152SDavid Daney goto no_cf; 9397ed18152SDavid Daney ranges = fdt_getprop_w(initial_boot_params, bootbus, "ranges", &len); 9407ed18152SDavid Daney if (!ranges || len < (5 * 8 * sizeof(__be32))) 9417ed18152SDavid Daney goto no_cf; 9427ed18152SDavid Daney 9437ed18152SDavid Daney ranges[(cs * 5) + 2] = cpu_to_be32(region_base >> 32); 9447ed18152SDavid Daney ranges[(cs * 5) + 3] = cpu_to_be32(region_base & 0xffffffff); 9457ed18152SDavid Daney ranges[(cs * 5) + 4] = cpu_to_be32(region_size); 9467ed18152SDavid Daney if (is_true_ide) { 9477ed18152SDavid Daney cs++; 9487ed18152SDavid Daney ranges[(cs * 5) + 2] = cpu_to_be32(region1_base >> 32); 9497ed18152SDavid Daney ranges[(cs * 5) + 3] = cpu_to_be32(region1_base & 0xffffffff); 9507ed18152SDavid Daney ranges[(cs * 5) + 4] = cpu_to_be32(region1_size); 9517ed18152SDavid Daney } 9527ed18152SDavid Daney goto end_cf; 9537ed18152SDavid Daney no_cf: 9547ed18152SDavid Daney fdt_nop_node(initial_boot_params, cf); 9557ed18152SDavid Daney 9567ed18152SDavid Daney end_cf: 9577ed18152SDavid Daney ; 9587ed18152SDavid Daney } 9597ed18152SDavid Daney 9607ed18152SDavid Daney /* 8 char LED */ 9617ed18152SDavid Daney alias_prop = fdt_getprop(initial_boot_params, aliases, 9627ed18152SDavid Daney "led0", NULL); 9637ed18152SDavid Daney if (alias_prop) { 9647ed18152SDavid Daney union cvmx_mio_boot_reg_cfgx mio_boot_reg_cfg; 9657ed18152SDavid Daney unsigned long base_ptr, region_base, region_size; 9667ed18152SDavid Daney int cs, bootbus; 9677ed18152SDavid Daney __be32 new_reg[6]; 9687ed18152SDavid Daney __be32 *ranges; 9697ed18152SDavid Daney int len; 9707ed18152SDavid Daney int led = fdt_path_offset(initial_boot_params, alias_prop); 9717ed18152SDavid Daney 9727ed18152SDavid Daney base_ptr = octeon_bootinfo->led_display_base_addr; 9737ed18152SDavid Daney if (base_ptr == 0) 9747ed18152SDavid Daney goto no_led; 9757ed18152SDavid Daney /* Find CS0 region. */ 9767ed18152SDavid Daney for (cs = 0; cs < 8; cs++) { 9777ed18152SDavid Daney mio_boot_reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs)); 9787ed18152SDavid Daney region_base = mio_boot_reg_cfg.s.base << 16; 9797ed18152SDavid Daney region_size = (mio_boot_reg_cfg.s.size + 1) << 16; 9807ed18152SDavid Daney if (mio_boot_reg_cfg.s.en && base_ptr >= region_base 9817ed18152SDavid Daney && base_ptr < region_base + region_size) 9827ed18152SDavid Daney break; 9837ed18152SDavid Daney } 9847ed18152SDavid Daney 9857ed18152SDavid Daney if (cs > 7) 9867ed18152SDavid Daney goto no_led; 9877ed18152SDavid Daney 9887ed18152SDavid Daney new_reg[0] = cpu_to_be32(cs); 9897ed18152SDavid Daney new_reg[1] = cpu_to_be32(0x20); 9907ed18152SDavid Daney new_reg[2] = cpu_to_be32(0x20); 9917ed18152SDavid Daney new_reg[3] = cpu_to_be32(cs); 9927ed18152SDavid Daney new_reg[4] = cpu_to_be32(0); 9937ed18152SDavid Daney new_reg[5] = cpu_to_be32(0x20); 9947ed18152SDavid Daney fdt_setprop_inplace(initial_boot_params, led, 9957ed18152SDavid Daney "reg", new_reg, sizeof(new_reg)); 9967ed18152SDavid Daney 9977ed18152SDavid Daney bootbus = fdt_parent_offset(initial_boot_params, led); 9987ed18152SDavid Daney if (bootbus < 0) 9997ed18152SDavid Daney goto no_led; 10007ed18152SDavid Daney ranges = fdt_getprop_w(initial_boot_params, bootbus, "ranges", &len); 10017ed18152SDavid Daney if (!ranges || len < (5 * 8 * sizeof(__be32))) 10027ed18152SDavid Daney goto no_led; 10037ed18152SDavid Daney 10047ed18152SDavid Daney ranges[(cs * 5) + 2] = cpu_to_be32(region_base >> 32); 10057ed18152SDavid Daney ranges[(cs * 5) + 3] = cpu_to_be32(region_base & 0xffffffff); 10067ed18152SDavid Daney ranges[(cs * 5) + 4] = cpu_to_be32(region_size); 10077ed18152SDavid Daney goto end_led; 10087ed18152SDavid Daney 10097ed18152SDavid Daney no_led: 10107ed18152SDavid Daney fdt_nop_node(initial_boot_params, led); 10117ed18152SDavid Daney end_led: 10127ed18152SDavid Daney ; 10137ed18152SDavid Daney } 10147ed18152SDavid Daney 10157fd57ab9SSteven J. Hill #ifdef CONFIG_USB 10167ed18152SDavid Daney /* OHCI/UHCI USB */ 10177ed18152SDavid Daney alias_prop = fdt_getprop(initial_boot_params, aliases, 10187ed18152SDavid Daney "uctl", NULL); 10197ed18152SDavid Daney if (alias_prop) { 10207ed18152SDavid Daney int uctl = fdt_path_offset(initial_boot_params, alias_prop); 10217ed18152SDavid Daney 10227ed18152SDavid Daney if (uctl >= 0 && (!OCTEON_IS_MODEL(OCTEON_CN6XXX) || 10237ed18152SDavid Daney octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC2E)) { 10247ed18152SDavid Daney pr_debug("Deleting uctl\n"); 10257ed18152SDavid Daney fdt_nop_node(initial_boot_params, uctl); 10267ed18152SDavid Daney fdt_nop_property(initial_boot_params, aliases, "uctl"); 10277ed18152SDavid Daney } else if (octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC10E || 10287ed18152SDavid Daney octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC4E) { 10297ed18152SDavid Daney /* Missing "refclk-type" defaults to crystal. */ 10307ed18152SDavid Daney fdt_nop_property(initial_boot_params, uctl, "refclk-type"); 10317ed18152SDavid Daney } 10327ed18152SDavid Daney } 10337ed18152SDavid Daney 1034d617f9e9SDavid Daney /* DWC2 USB */ 1035d617f9e9SDavid Daney alias_prop = fdt_getprop(initial_boot_params, aliases, 1036d617f9e9SDavid Daney "usbn", NULL); 1037d617f9e9SDavid Daney if (alias_prop) { 1038d617f9e9SDavid Daney int usbn = fdt_path_offset(initial_boot_params, alias_prop); 1039d617f9e9SDavid Daney 1040d617f9e9SDavid Daney if (usbn >= 0 && (current_cpu_type() == CPU_CAVIUM_OCTEON2 || 1041d617f9e9SDavid Daney !octeon_has_feature(OCTEON_FEATURE_USB))) { 1042d617f9e9SDavid Daney pr_debug("Deleting usbn\n"); 1043d617f9e9SDavid Daney fdt_nop_node(initial_boot_params, usbn); 1044d617f9e9SDavid Daney fdt_nop_property(initial_boot_params, aliases, "usbn"); 1045d617f9e9SDavid Daney } else { 1046d617f9e9SDavid Daney __be32 new_f[1]; 1047d617f9e9SDavid Daney enum cvmx_helper_board_usb_clock_types c; 1048e96b1b06SSteven J. Hill 1049d617f9e9SDavid Daney c = __cvmx_helper_board_usb_get_clock_type(); 1050d617f9e9SDavid Daney switch (c) { 1051d617f9e9SDavid Daney case USB_CLOCK_TYPE_REF_48: 1052d617f9e9SDavid Daney new_f[0] = cpu_to_be32(48000000); 1053d617f9e9SDavid Daney fdt_setprop_inplace(initial_boot_params, usbn, 1054d617f9e9SDavid Daney "refclk-frequency", new_f, sizeof(new_f)); 1055d617f9e9SDavid Daney /* Fall through ...*/ 1056d617f9e9SDavid Daney case USB_CLOCK_TYPE_REF_12: 1057d617f9e9SDavid Daney /* Missing "refclk-type" defaults to external. */ 1058d617f9e9SDavid Daney fdt_nop_property(initial_boot_params, usbn, "refclk-type"); 1059d617f9e9SDavid Daney break; 1060d617f9e9SDavid Daney default: 1061d617f9e9SDavid Daney break; 1062d617f9e9SDavid Daney } 1063d617f9e9SDavid Daney } 1064d617f9e9SDavid Daney } 10657fd57ab9SSteven J. Hill #endif 1066d617f9e9SDavid Daney 10677ed18152SDavid Daney return 0; 10687ed18152SDavid Daney } 10697ed18152SDavid Daney 10707ed18152SDavid Daney static int __init octeon_publish_devices(void) 10717ed18152SDavid Daney { 1072f072f9ceSRob Herring return of_platform_populate(NULL, octeon_ids, NULL, NULL); 10737ed18152SDavid Daney } 10748074d782SAaro Koskinen arch_initcall(octeon_publish_devices); 1075