162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 362306a36Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 462306a36Sopenharmony_ci * for more details. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2004-2017 Cavium, Inc. 762306a36Sopenharmony_ci * Copyright (C) 2008 Wind River Systems 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/etherdevice.h> 1162306a36Sopenharmony_ci#include <linux/of.h> 1262306a36Sopenharmony_ci#include <linux/of_platform.h> 1362306a36Sopenharmony_ci#include <linux/of_fdt.h> 1462306a36Sopenharmony_ci#include <linux/platform_device.h> 1562306a36Sopenharmony_ci#include <linux/libfdt.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <asm/octeon/octeon.h> 1862306a36Sopenharmony_ci#include <asm/octeon/cvmx-helper-board.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#ifdef CONFIG_USB 2162306a36Sopenharmony_ci#include <linux/usb/ehci_def.h> 2262306a36Sopenharmony_ci#include <linux/usb/ehci_pdriver.h> 2362306a36Sopenharmony_ci#include <linux/usb/ohci_pdriver.h> 2462306a36Sopenharmony_ci#include <asm/octeon/cvmx-uctlx-defs.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define CVMX_UAHCX_EHCI_USBCMD (CVMX_ADD_IO_SEG(0x00016F0000000010ull)) 2762306a36Sopenharmony_ci#define CVMX_UAHCX_OHCI_USBCMD (CVMX_ADD_IO_SEG(0x00016F0000000408ull)) 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic DEFINE_MUTEX(octeon2_usb_clocks_mutex); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic int octeon2_usb_clock_start_cnt; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic int __init octeon2_usb_reset(void) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci union cvmx_uctlx_clk_rst_ctl clk_rst_ctl; 3662306a36Sopenharmony_ci u32 ucmd; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci if (!OCTEON_IS_OCTEON2()) 3962306a36Sopenharmony_ci return 0; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0)); 4262306a36Sopenharmony_ci if (clk_rst_ctl.s.hrst) { 4362306a36Sopenharmony_ci ucmd = cvmx_read64_uint32(CVMX_UAHCX_EHCI_USBCMD); 4462306a36Sopenharmony_ci ucmd &= ~CMD_RUN; 4562306a36Sopenharmony_ci cvmx_write64_uint32(CVMX_UAHCX_EHCI_USBCMD, ucmd); 4662306a36Sopenharmony_ci mdelay(2); 4762306a36Sopenharmony_ci ucmd |= CMD_RESET; 4862306a36Sopenharmony_ci cvmx_write64_uint32(CVMX_UAHCX_EHCI_USBCMD, ucmd); 4962306a36Sopenharmony_ci ucmd = cvmx_read64_uint32(CVMX_UAHCX_OHCI_USBCMD); 5062306a36Sopenharmony_ci ucmd |= CMD_RUN; 5162306a36Sopenharmony_ci cvmx_write64_uint32(CVMX_UAHCX_OHCI_USBCMD, ucmd); 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci return 0; 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ciarch_initcall(octeon2_usb_reset); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic void octeon2_usb_clocks_start(struct device *dev) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci u64 div; 6162306a36Sopenharmony_ci union cvmx_uctlx_if_ena if_ena; 6262306a36Sopenharmony_ci union cvmx_uctlx_clk_rst_ctl clk_rst_ctl; 6362306a36Sopenharmony_ci union cvmx_uctlx_uphy_portx_ctl_status port_ctl_status; 6462306a36Sopenharmony_ci int i; 6562306a36Sopenharmony_ci unsigned long io_clk_64_to_ns; 6662306a36Sopenharmony_ci u32 clock_rate = 12000000; 6762306a36Sopenharmony_ci bool is_crystal_clock = false; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci mutex_lock(&octeon2_usb_clocks_mutex); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci octeon2_usb_clock_start_cnt++; 7362306a36Sopenharmony_ci if (octeon2_usb_clock_start_cnt != 1) 7462306a36Sopenharmony_ci goto exit; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci io_clk_64_to_ns = 64000000000ull / octeon_get_io_clock_rate(); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci if (dev->of_node) { 7962306a36Sopenharmony_ci struct device_node *uctl_node; 8062306a36Sopenharmony_ci const char *clock_type; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci uctl_node = of_get_parent(dev->of_node); 8362306a36Sopenharmony_ci if (!uctl_node) { 8462306a36Sopenharmony_ci dev_err(dev, "No UCTL device node\n"); 8562306a36Sopenharmony_ci goto exit; 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci i = of_property_read_u32(uctl_node, 8862306a36Sopenharmony_ci "refclk-frequency", &clock_rate); 8962306a36Sopenharmony_ci if (i) { 9062306a36Sopenharmony_ci dev_err(dev, "No UCTL \"refclk-frequency\"\n"); 9162306a36Sopenharmony_ci of_node_put(uctl_node); 9262306a36Sopenharmony_ci goto exit; 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci i = of_property_read_string(uctl_node, 9562306a36Sopenharmony_ci "refclk-type", &clock_type); 9662306a36Sopenharmony_ci of_node_put(uctl_node); 9762306a36Sopenharmony_ci if (!i && strcmp("crystal", clock_type) == 0) 9862306a36Sopenharmony_ci is_crystal_clock = true; 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci /* 10262306a36Sopenharmony_ci * Step 1: Wait for voltages stable. That surely happened 10362306a36Sopenharmony_ci * before starting the kernel. 10462306a36Sopenharmony_ci * 10562306a36Sopenharmony_ci * Step 2: Enable SCLK of UCTL by writing UCTL0_IF_ENA[EN] = 1 10662306a36Sopenharmony_ci */ 10762306a36Sopenharmony_ci if_ena.u64 = 0; 10862306a36Sopenharmony_ci if_ena.s.en = 1; 10962306a36Sopenharmony_ci cvmx_write_csr(CVMX_UCTLX_IF_ENA(0), if_ena.u64); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci for (i = 0; i <= 1; i++) { 11262306a36Sopenharmony_ci port_ctl_status.u64 = 11362306a36Sopenharmony_ci cvmx_read_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0)); 11462306a36Sopenharmony_ci /* Set txvreftune to 15 to obtain compliant 'eye' diagram. */ 11562306a36Sopenharmony_ci port_ctl_status.s.txvreftune = 15; 11662306a36Sopenharmony_ci port_ctl_status.s.txrisetune = 1; 11762306a36Sopenharmony_ci port_ctl_status.s.txpreemphasistune = 1; 11862306a36Sopenharmony_ci cvmx_write_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0), 11962306a36Sopenharmony_ci port_ctl_status.u64); 12062306a36Sopenharmony_ci } 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci /* Step 3: Configure the reference clock, PHY, and HCLK */ 12362306a36Sopenharmony_ci clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0)); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci /* 12662306a36Sopenharmony_ci * If the UCTL looks like it has already been started, skip 12762306a36Sopenharmony_ci * the initialization, otherwise bus errors are obtained. 12862306a36Sopenharmony_ci */ 12962306a36Sopenharmony_ci if (clk_rst_ctl.s.hrst) 13062306a36Sopenharmony_ci goto end_clock; 13162306a36Sopenharmony_ci /* 3a */ 13262306a36Sopenharmony_ci clk_rst_ctl.s.p_por = 1; 13362306a36Sopenharmony_ci clk_rst_ctl.s.hrst = 0; 13462306a36Sopenharmony_ci clk_rst_ctl.s.p_prst = 0; 13562306a36Sopenharmony_ci clk_rst_ctl.s.h_clkdiv_rst = 0; 13662306a36Sopenharmony_ci clk_rst_ctl.s.o_clkdiv_rst = 0; 13762306a36Sopenharmony_ci clk_rst_ctl.s.h_clkdiv_en = 0; 13862306a36Sopenharmony_ci clk_rst_ctl.s.o_clkdiv_en = 0; 13962306a36Sopenharmony_ci cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci /* 3b */ 14262306a36Sopenharmony_ci clk_rst_ctl.s.p_refclk_sel = is_crystal_clock ? 0 : 1; 14362306a36Sopenharmony_ci switch (clock_rate) { 14462306a36Sopenharmony_ci default: 14562306a36Sopenharmony_ci pr_err("Invalid UCTL clock rate of %u, using 12000000 instead\n", 14662306a36Sopenharmony_ci clock_rate); 14762306a36Sopenharmony_ci fallthrough; 14862306a36Sopenharmony_ci case 12000000: 14962306a36Sopenharmony_ci clk_rst_ctl.s.p_refclk_div = 0; 15062306a36Sopenharmony_ci break; 15162306a36Sopenharmony_ci case 24000000: 15262306a36Sopenharmony_ci clk_rst_ctl.s.p_refclk_div = 1; 15362306a36Sopenharmony_ci break; 15462306a36Sopenharmony_ci case 48000000: 15562306a36Sopenharmony_ci clk_rst_ctl.s.p_refclk_div = 2; 15662306a36Sopenharmony_ci break; 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci /* 3c */ 16162306a36Sopenharmony_ci div = octeon_get_io_clock_rate() / 130000000ull; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci switch (div) { 16462306a36Sopenharmony_ci case 0: 16562306a36Sopenharmony_ci div = 1; 16662306a36Sopenharmony_ci break; 16762306a36Sopenharmony_ci case 1: 16862306a36Sopenharmony_ci case 2: 16962306a36Sopenharmony_ci case 3: 17062306a36Sopenharmony_ci case 4: 17162306a36Sopenharmony_ci break; 17262306a36Sopenharmony_ci case 5: 17362306a36Sopenharmony_ci div = 4; 17462306a36Sopenharmony_ci break; 17562306a36Sopenharmony_ci case 6: 17662306a36Sopenharmony_ci case 7: 17762306a36Sopenharmony_ci div = 6; 17862306a36Sopenharmony_ci break; 17962306a36Sopenharmony_ci case 8: 18062306a36Sopenharmony_ci case 9: 18162306a36Sopenharmony_ci case 10: 18262306a36Sopenharmony_ci case 11: 18362306a36Sopenharmony_ci div = 8; 18462306a36Sopenharmony_ci break; 18562306a36Sopenharmony_ci default: 18662306a36Sopenharmony_ci div = 12; 18762306a36Sopenharmony_ci break; 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci clk_rst_ctl.s.h_div = div; 19062306a36Sopenharmony_ci cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 19162306a36Sopenharmony_ci /* Read it back, */ 19262306a36Sopenharmony_ci clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0)); 19362306a36Sopenharmony_ci clk_rst_ctl.s.h_clkdiv_en = 1; 19462306a36Sopenharmony_ci cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 19562306a36Sopenharmony_ci /* 3d */ 19662306a36Sopenharmony_ci clk_rst_ctl.s.h_clkdiv_rst = 1; 19762306a36Sopenharmony_ci cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci /* 3e: delay 64 io clocks */ 20062306a36Sopenharmony_ci ndelay(io_clk_64_to_ns); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci /* 20362306a36Sopenharmony_ci * Step 4: Program the power-on reset field in the UCTL 20462306a36Sopenharmony_ci * clock-reset-control register. 20562306a36Sopenharmony_ci */ 20662306a36Sopenharmony_ci clk_rst_ctl.s.p_por = 0; 20762306a36Sopenharmony_ci cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci /* Step 5: Wait 3 ms for the PHY clock to start. */ 21062306a36Sopenharmony_ci mdelay(3); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci /* Steps 6..9 for ATE only, are skipped. */ 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci /* Step 10: Configure the OHCI_CLK48 and OHCI_CLK12 clocks. */ 21562306a36Sopenharmony_ci /* 10a */ 21662306a36Sopenharmony_ci clk_rst_ctl.s.o_clkdiv_rst = 1; 21762306a36Sopenharmony_ci cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci /* 10b */ 22062306a36Sopenharmony_ci clk_rst_ctl.s.o_clkdiv_en = 1; 22162306a36Sopenharmony_ci cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci /* 10c */ 22462306a36Sopenharmony_ci ndelay(io_clk_64_to_ns); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci /* 22762306a36Sopenharmony_ci * Step 11: Program the PHY reset field: 22862306a36Sopenharmony_ci * UCTL0_CLK_RST_CTL[P_PRST] = 1 22962306a36Sopenharmony_ci */ 23062306a36Sopenharmony_ci clk_rst_ctl.s.p_prst = 1; 23162306a36Sopenharmony_ci cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci /* Step 11b */ 23462306a36Sopenharmony_ci udelay(1); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci /* Step 11c */ 23762306a36Sopenharmony_ci clk_rst_ctl.s.p_prst = 0; 23862306a36Sopenharmony_ci cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci /* Step 11d */ 24162306a36Sopenharmony_ci mdelay(1); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci /* Step 11e */ 24462306a36Sopenharmony_ci clk_rst_ctl.s.p_prst = 1; 24562306a36Sopenharmony_ci cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci /* Step 12: Wait 1 uS. */ 24862306a36Sopenharmony_ci udelay(1); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci /* Step 13: Program the HRESET_N field: UCTL0_CLK_RST_CTL[HRST] = 1 */ 25162306a36Sopenharmony_ci clk_rst_ctl.s.hrst = 1; 25262306a36Sopenharmony_ci cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ciend_clock: 25562306a36Sopenharmony_ci /* Set uSOF cycle period to 60,000 bits. */ 25662306a36Sopenharmony_ci cvmx_write_csr(CVMX_UCTLX_EHCI_FLA(0), 0x20ull); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ciexit: 25962306a36Sopenharmony_ci mutex_unlock(&octeon2_usb_clocks_mutex); 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic void octeon2_usb_clocks_stop(void) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci mutex_lock(&octeon2_usb_clocks_mutex); 26562306a36Sopenharmony_ci octeon2_usb_clock_start_cnt--; 26662306a36Sopenharmony_ci mutex_unlock(&octeon2_usb_clocks_mutex); 26762306a36Sopenharmony_ci} 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cistatic int octeon_ehci_power_on(struct platform_device *pdev) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci octeon2_usb_clocks_start(&pdev->dev); 27262306a36Sopenharmony_ci return 0; 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistatic void octeon_ehci_power_off(struct platform_device *pdev) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci octeon2_usb_clocks_stop(); 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cistatic struct usb_ehci_pdata octeon_ehci_pdata = { 28162306a36Sopenharmony_ci /* Octeon EHCI matches CPU endianness. */ 28262306a36Sopenharmony_ci#ifdef __BIG_ENDIAN 28362306a36Sopenharmony_ci .big_endian_mmio = 1, 28462306a36Sopenharmony_ci#endif 28562306a36Sopenharmony_ci /* 28662306a36Sopenharmony_ci * We can DMA from anywhere. But the descriptors must be in 28762306a36Sopenharmony_ci * the lower 4GB. 28862306a36Sopenharmony_ci */ 28962306a36Sopenharmony_ci .dma_mask_64 = 0, 29062306a36Sopenharmony_ci .power_on = octeon_ehci_power_on, 29162306a36Sopenharmony_ci .power_off = octeon_ehci_power_off, 29262306a36Sopenharmony_ci}; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cistatic void __init octeon_ehci_hw_start(struct device *dev) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci union cvmx_uctlx_ehci_ctl ehci_ctl; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci octeon2_usb_clocks_start(dev); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci ehci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_EHCI_CTL(0)); 30162306a36Sopenharmony_ci /* Use 64-bit addressing. */ 30262306a36Sopenharmony_ci ehci_ctl.s.ehci_64b_addr_en = 1; 30362306a36Sopenharmony_ci ehci_ctl.s.l2c_addr_msb = 0; 30462306a36Sopenharmony_ci#ifdef __BIG_ENDIAN 30562306a36Sopenharmony_ci ehci_ctl.s.l2c_buff_emod = 1; /* Byte swapped. */ 30662306a36Sopenharmony_ci ehci_ctl.s.l2c_desc_emod = 1; /* Byte swapped. */ 30762306a36Sopenharmony_ci#else 30862306a36Sopenharmony_ci ehci_ctl.s.l2c_buff_emod = 0; /* not swapped. */ 30962306a36Sopenharmony_ci ehci_ctl.s.l2c_desc_emod = 0; /* not swapped. */ 31062306a36Sopenharmony_ci ehci_ctl.s.inv_reg_a2 = 1; 31162306a36Sopenharmony_ci#endif 31262306a36Sopenharmony_ci cvmx_write_csr(CVMX_UCTLX_EHCI_CTL(0), ehci_ctl.u64); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci octeon2_usb_clocks_stop(); 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cistatic int __init octeon_ehci_device_init(void) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci struct platform_device *pd; 32062306a36Sopenharmony_ci struct device_node *ehci_node; 32162306a36Sopenharmony_ci int ret = 0; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci ehci_node = of_find_node_by_name(NULL, "ehci"); 32462306a36Sopenharmony_ci if (!ehci_node) 32562306a36Sopenharmony_ci return 0; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci pd = of_find_device_by_node(ehci_node); 32862306a36Sopenharmony_ci of_node_put(ehci_node); 32962306a36Sopenharmony_ci if (!pd) 33062306a36Sopenharmony_ci return 0; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci pd->dev.platform_data = &octeon_ehci_pdata; 33362306a36Sopenharmony_ci octeon_ehci_hw_start(&pd->dev); 33462306a36Sopenharmony_ci put_device(&pd->dev); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci return ret; 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_cidevice_initcall(octeon_ehci_device_init); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cistatic int octeon_ohci_power_on(struct platform_device *pdev) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci octeon2_usb_clocks_start(&pdev->dev); 34362306a36Sopenharmony_ci return 0; 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_cistatic void octeon_ohci_power_off(struct platform_device *pdev) 34762306a36Sopenharmony_ci{ 34862306a36Sopenharmony_ci octeon2_usb_clocks_stop(); 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cistatic struct usb_ohci_pdata octeon_ohci_pdata = { 35262306a36Sopenharmony_ci /* Octeon OHCI matches CPU endianness. */ 35362306a36Sopenharmony_ci#ifdef __BIG_ENDIAN 35462306a36Sopenharmony_ci .big_endian_mmio = 1, 35562306a36Sopenharmony_ci#endif 35662306a36Sopenharmony_ci .power_on = octeon_ohci_power_on, 35762306a36Sopenharmony_ci .power_off = octeon_ohci_power_off, 35862306a36Sopenharmony_ci}; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_cistatic void __init octeon_ohci_hw_start(struct device *dev) 36162306a36Sopenharmony_ci{ 36262306a36Sopenharmony_ci union cvmx_uctlx_ohci_ctl ohci_ctl; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci octeon2_usb_clocks_start(dev); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci ohci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_OHCI_CTL(0)); 36762306a36Sopenharmony_ci ohci_ctl.s.l2c_addr_msb = 0; 36862306a36Sopenharmony_ci#ifdef __BIG_ENDIAN 36962306a36Sopenharmony_ci ohci_ctl.s.l2c_buff_emod = 1; /* Byte swapped. */ 37062306a36Sopenharmony_ci ohci_ctl.s.l2c_desc_emod = 1; /* Byte swapped. */ 37162306a36Sopenharmony_ci#else 37262306a36Sopenharmony_ci ohci_ctl.s.l2c_buff_emod = 0; /* not swapped. */ 37362306a36Sopenharmony_ci ohci_ctl.s.l2c_desc_emod = 0; /* not swapped. */ 37462306a36Sopenharmony_ci ohci_ctl.s.inv_reg_a2 = 1; 37562306a36Sopenharmony_ci#endif 37662306a36Sopenharmony_ci cvmx_write_csr(CVMX_UCTLX_OHCI_CTL(0), ohci_ctl.u64); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci octeon2_usb_clocks_stop(); 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_cistatic int __init octeon_ohci_device_init(void) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci struct platform_device *pd; 38462306a36Sopenharmony_ci struct device_node *ohci_node; 38562306a36Sopenharmony_ci int ret = 0; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci ohci_node = of_find_node_by_name(NULL, "ohci"); 38862306a36Sopenharmony_ci if (!ohci_node) 38962306a36Sopenharmony_ci return 0; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci pd = of_find_device_by_node(ohci_node); 39262306a36Sopenharmony_ci of_node_put(ohci_node); 39362306a36Sopenharmony_ci if (!pd) 39462306a36Sopenharmony_ci return 0; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci pd->dev.platform_data = &octeon_ohci_pdata; 39762306a36Sopenharmony_ci octeon_ohci_hw_start(&pd->dev); 39862306a36Sopenharmony_ci put_device(&pd->dev); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci return ret; 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_cidevice_initcall(octeon_ohci_device_init); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci#endif /* CONFIG_USB */ 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci/* Octeon Random Number Generator. */ 40762306a36Sopenharmony_cistatic int __init octeon_rng_device_init(void) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci struct platform_device *pd; 41062306a36Sopenharmony_ci int ret = 0; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci struct resource rng_resources[] = { 41362306a36Sopenharmony_ci { 41462306a36Sopenharmony_ci .flags = IORESOURCE_MEM, 41562306a36Sopenharmony_ci .start = XKPHYS_TO_PHYS(CVMX_RNM_CTL_STATUS), 41662306a36Sopenharmony_ci .end = XKPHYS_TO_PHYS(CVMX_RNM_CTL_STATUS) + 0xf 41762306a36Sopenharmony_ci }, { 41862306a36Sopenharmony_ci .flags = IORESOURCE_MEM, 41962306a36Sopenharmony_ci .start = cvmx_build_io_address(8, 0), 42062306a36Sopenharmony_ci .end = cvmx_build_io_address(8, 0) + 0x7 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci }; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci pd = platform_device_alloc("octeon_rng", -1); 42562306a36Sopenharmony_ci if (!pd) { 42662306a36Sopenharmony_ci ret = -ENOMEM; 42762306a36Sopenharmony_ci goto out; 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci ret = platform_device_add_resources(pd, rng_resources, 43162306a36Sopenharmony_ci ARRAY_SIZE(rng_resources)); 43262306a36Sopenharmony_ci if (ret) 43362306a36Sopenharmony_ci goto fail; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci ret = platform_device_add(pd); 43662306a36Sopenharmony_ci if (ret) 43762306a36Sopenharmony_ci goto fail; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci return ret; 44062306a36Sopenharmony_cifail: 44162306a36Sopenharmony_ci platform_device_put(pd); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ciout: 44462306a36Sopenharmony_ci return ret; 44562306a36Sopenharmony_ci} 44662306a36Sopenharmony_cidevice_initcall(octeon_rng_device_init); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_cistatic const struct of_device_id octeon_ids[] __initconst = { 44962306a36Sopenharmony_ci { .compatible = "simple-bus", }, 45062306a36Sopenharmony_ci { .compatible = "cavium,octeon-6335-uctl", }, 45162306a36Sopenharmony_ci { .compatible = "cavium,octeon-5750-usbn", }, 45262306a36Sopenharmony_ci { .compatible = "cavium,octeon-3860-bootbus", }, 45362306a36Sopenharmony_ci { .compatible = "cavium,mdio-mux", }, 45462306a36Sopenharmony_ci { .compatible = "gpio-leds", }, 45562306a36Sopenharmony_ci {}, 45662306a36Sopenharmony_ci}; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_cistatic bool __init octeon_has_88e1145(void) 45962306a36Sopenharmony_ci{ 46062306a36Sopenharmony_ci return !OCTEON_IS_MODEL(OCTEON_CN52XX) && 46162306a36Sopenharmony_ci !OCTEON_IS_MODEL(OCTEON_CN6XXX) && 46262306a36Sopenharmony_ci !OCTEON_IS_MODEL(OCTEON_CN56XX); 46362306a36Sopenharmony_ci} 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cistatic bool __init octeon_has_fixed_link(int ipd_port) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci switch (cvmx_sysinfo_get()->board_type) { 46862306a36Sopenharmony_ci case CVMX_BOARD_TYPE_CN3005_EVB_HS5: 46962306a36Sopenharmony_ci case CVMX_BOARD_TYPE_CN3010_EVB_HS5: 47062306a36Sopenharmony_ci case CVMX_BOARD_TYPE_CN3020_EVB_HS5: 47162306a36Sopenharmony_ci case CVMX_BOARD_TYPE_CUST_NB5: 47262306a36Sopenharmony_ci case CVMX_BOARD_TYPE_EBH3100: 47362306a36Sopenharmony_ci /* Port 1 on these boards is always gigabit. */ 47462306a36Sopenharmony_ci return ipd_port == 1; 47562306a36Sopenharmony_ci case CVMX_BOARD_TYPE_BBGW_REF: 47662306a36Sopenharmony_ci /* Ports 0 and 1 connect to the switch. */ 47762306a36Sopenharmony_ci return ipd_port == 0 || ipd_port == 1; 47862306a36Sopenharmony_ci } 47962306a36Sopenharmony_ci return false; 48062306a36Sopenharmony_ci} 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_cistatic void __init octeon_fdt_set_phy(int eth, int phy_addr) 48362306a36Sopenharmony_ci{ 48462306a36Sopenharmony_ci const __be32 *phy_handle; 48562306a36Sopenharmony_ci const __be32 *alt_phy_handle; 48662306a36Sopenharmony_ci const __be32 *reg; 48762306a36Sopenharmony_ci u32 phandle; 48862306a36Sopenharmony_ci int phy; 48962306a36Sopenharmony_ci int alt_phy; 49062306a36Sopenharmony_ci const char *p; 49162306a36Sopenharmony_ci int current_len; 49262306a36Sopenharmony_ci char new_name[20]; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci phy_handle = fdt_getprop(initial_boot_params, eth, "phy-handle", NULL); 49562306a36Sopenharmony_ci if (!phy_handle) 49662306a36Sopenharmony_ci return; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci phandle = be32_to_cpup(phy_handle); 49962306a36Sopenharmony_ci phy = fdt_node_offset_by_phandle(initial_boot_params, phandle); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci alt_phy_handle = fdt_getprop(initial_boot_params, eth, "cavium,alt-phy-handle", NULL); 50262306a36Sopenharmony_ci if (alt_phy_handle) { 50362306a36Sopenharmony_ci u32 alt_phandle = be32_to_cpup(alt_phy_handle); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci alt_phy = fdt_node_offset_by_phandle(initial_boot_params, alt_phandle); 50662306a36Sopenharmony_ci } else { 50762306a36Sopenharmony_ci alt_phy = -1; 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci if (phy_addr < 0 || phy < 0) { 51162306a36Sopenharmony_ci /* Delete the PHY things */ 51262306a36Sopenharmony_ci fdt_nop_property(initial_boot_params, eth, "phy-handle"); 51362306a36Sopenharmony_ci /* This one may fail */ 51462306a36Sopenharmony_ci fdt_nop_property(initial_boot_params, eth, "cavium,alt-phy-handle"); 51562306a36Sopenharmony_ci if (phy >= 0) 51662306a36Sopenharmony_ci fdt_nop_node(initial_boot_params, phy); 51762306a36Sopenharmony_ci if (alt_phy >= 0) 51862306a36Sopenharmony_ci fdt_nop_node(initial_boot_params, alt_phy); 51962306a36Sopenharmony_ci return; 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci if (phy_addr >= 256 && alt_phy > 0) { 52362306a36Sopenharmony_ci const struct fdt_property *phy_prop; 52462306a36Sopenharmony_ci struct fdt_property *alt_prop; 52562306a36Sopenharmony_ci fdt32_t phy_handle_name; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci /* Use the alt phy node instead.*/ 52862306a36Sopenharmony_ci phy_prop = fdt_get_property(initial_boot_params, eth, "phy-handle", NULL); 52962306a36Sopenharmony_ci phy_handle_name = phy_prop->nameoff; 53062306a36Sopenharmony_ci fdt_nop_node(initial_boot_params, phy); 53162306a36Sopenharmony_ci fdt_nop_property(initial_boot_params, eth, "phy-handle"); 53262306a36Sopenharmony_ci alt_prop = fdt_get_property_w(initial_boot_params, eth, "cavium,alt-phy-handle", NULL); 53362306a36Sopenharmony_ci alt_prop->nameoff = phy_handle_name; 53462306a36Sopenharmony_ci phy = alt_phy; 53562306a36Sopenharmony_ci } 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci phy_addr &= 0xff; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci if (octeon_has_88e1145()) { 54062306a36Sopenharmony_ci fdt_nop_property(initial_boot_params, phy, "marvell,reg-init"); 54162306a36Sopenharmony_ci memset(new_name, 0, sizeof(new_name)); 54262306a36Sopenharmony_ci strcpy(new_name, "marvell,88e1145"); 54362306a36Sopenharmony_ci p = fdt_getprop(initial_boot_params, phy, "compatible", 54462306a36Sopenharmony_ci ¤t_len); 54562306a36Sopenharmony_ci if (p && current_len >= strlen(new_name)) 54662306a36Sopenharmony_ci fdt_setprop_inplace(initial_boot_params, phy, 54762306a36Sopenharmony_ci "compatible", new_name, current_len); 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci reg = fdt_getprop(initial_boot_params, phy, "reg", NULL); 55162306a36Sopenharmony_ci if (phy_addr == be32_to_cpup(reg)) 55262306a36Sopenharmony_ci return; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci fdt_setprop_inplace_cell(initial_boot_params, phy, "reg", phy_addr); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci snprintf(new_name, sizeof(new_name), "ethernet-phy@%x", phy_addr); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci p = fdt_get_name(initial_boot_params, phy, ¤t_len); 55962306a36Sopenharmony_ci if (p && current_len == strlen(new_name)) 56062306a36Sopenharmony_ci fdt_set_name(initial_boot_params, phy, new_name); 56162306a36Sopenharmony_ci else 56262306a36Sopenharmony_ci pr_err("Error: could not rename ethernet phy: <%s>", p); 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_cistatic void __init octeon_fdt_set_mac_addr(int n, u64 *pmac) 56662306a36Sopenharmony_ci{ 56762306a36Sopenharmony_ci const u8 *old_mac; 56862306a36Sopenharmony_ci int old_len; 56962306a36Sopenharmony_ci u8 new_mac[6]; 57062306a36Sopenharmony_ci u64 mac = *pmac; 57162306a36Sopenharmony_ci int r; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci old_mac = fdt_getprop(initial_boot_params, n, "local-mac-address", 57462306a36Sopenharmony_ci &old_len); 57562306a36Sopenharmony_ci if (!old_mac || old_len != 6 || is_valid_ether_addr(old_mac)) 57662306a36Sopenharmony_ci return; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci new_mac[0] = (mac >> 40) & 0xff; 57962306a36Sopenharmony_ci new_mac[1] = (mac >> 32) & 0xff; 58062306a36Sopenharmony_ci new_mac[2] = (mac >> 24) & 0xff; 58162306a36Sopenharmony_ci new_mac[3] = (mac >> 16) & 0xff; 58262306a36Sopenharmony_ci new_mac[4] = (mac >> 8) & 0xff; 58362306a36Sopenharmony_ci new_mac[5] = mac & 0xff; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci r = fdt_setprop_inplace(initial_boot_params, n, "local-mac-address", 58662306a36Sopenharmony_ci new_mac, sizeof(new_mac)); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci if (r) { 58962306a36Sopenharmony_ci pr_err("Setting \"local-mac-address\" failed %d", r); 59062306a36Sopenharmony_ci return; 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci *pmac = mac + 1; 59362306a36Sopenharmony_ci} 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_cistatic void __init octeon_fdt_rm_ethernet(int node) 59662306a36Sopenharmony_ci{ 59762306a36Sopenharmony_ci const __be32 *phy_handle; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci phy_handle = fdt_getprop(initial_boot_params, node, "phy-handle", NULL); 60062306a36Sopenharmony_ci if (phy_handle) { 60162306a36Sopenharmony_ci u32 ph = be32_to_cpup(phy_handle); 60262306a36Sopenharmony_ci int p = fdt_node_offset_by_phandle(initial_boot_params, ph); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci if (p >= 0) 60562306a36Sopenharmony_ci fdt_nop_node(initial_boot_params, p); 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci fdt_nop_node(initial_boot_params, node); 60862306a36Sopenharmony_ci} 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_cistatic void __init _octeon_rx_tx_delay(int eth, int rx_delay, int tx_delay) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci fdt_setprop_inplace_cell(initial_boot_params, eth, "rx-delay", 61362306a36Sopenharmony_ci rx_delay); 61462306a36Sopenharmony_ci fdt_setprop_inplace_cell(initial_boot_params, eth, "tx-delay", 61562306a36Sopenharmony_ci tx_delay); 61662306a36Sopenharmony_ci} 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_cistatic void __init octeon_rx_tx_delay(int eth, int iface, int port) 61962306a36Sopenharmony_ci{ 62062306a36Sopenharmony_ci switch (cvmx_sysinfo_get()->board_type) { 62162306a36Sopenharmony_ci case CVMX_BOARD_TYPE_CN3005_EVB_HS5: 62262306a36Sopenharmony_ci if (iface == 0) { 62362306a36Sopenharmony_ci if (port == 0) { 62462306a36Sopenharmony_ci /* 62562306a36Sopenharmony_ci * Boards with gigabit WAN ports need a 62662306a36Sopenharmony_ci * different setting that is compatible with 62762306a36Sopenharmony_ci * 100 Mbit settings 62862306a36Sopenharmony_ci */ 62962306a36Sopenharmony_ci _octeon_rx_tx_delay(eth, 0xc, 0x0c); 63062306a36Sopenharmony_ci return; 63162306a36Sopenharmony_ci } else if (port == 1) { 63262306a36Sopenharmony_ci /* Different config for switch port. */ 63362306a36Sopenharmony_ci _octeon_rx_tx_delay(eth, 0x0, 0x0); 63462306a36Sopenharmony_ci return; 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci } 63762306a36Sopenharmony_ci break; 63862306a36Sopenharmony_ci case CVMX_BOARD_TYPE_UBNT_E100: 63962306a36Sopenharmony_ci if (iface == 0 && port <= 2) { 64062306a36Sopenharmony_ci _octeon_rx_tx_delay(eth, 0x0, 0x10); 64162306a36Sopenharmony_ci return; 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci break; 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci fdt_nop_property(initial_boot_params, eth, "rx-delay"); 64662306a36Sopenharmony_ci fdt_nop_property(initial_boot_params, eth, "tx-delay"); 64762306a36Sopenharmony_ci} 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_cistatic void __init octeon_fdt_pip_port(int iface, int i, int p, int max) 65062306a36Sopenharmony_ci{ 65162306a36Sopenharmony_ci char name_buffer[20]; 65262306a36Sopenharmony_ci int eth; 65362306a36Sopenharmony_ci int phy_addr; 65462306a36Sopenharmony_ci int ipd_port; 65562306a36Sopenharmony_ci int fixed_link; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci snprintf(name_buffer, sizeof(name_buffer), "ethernet@%x", p); 65862306a36Sopenharmony_ci eth = fdt_subnode_offset(initial_boot_params, iface, name_buffer); 65962306a36Sopenharmony_ci if (eth < 0) 66062306a36Sopenharmony_ci return; 66162306a36Sopenharmony_ci if (p > max) { 66262306a36Sopenharmony_ci pr_debug("Deleting port %x:%x\n", i, p); 66362306a36Sopenharmony_ci octeon_fdt_rm_ethernet(eth); 66462306a36Sopenharmony_ci return; 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN68XX)) 66762306a36Sopenharmony_ci ipd_port = (0x100 * i) + (0x10 * p) + 0x800; 66862306a36Sopenharmony_ci else 66962306a36Sopenharmony_ci ipd_port = 16 * i + p; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci phy_addr = cvmx_helper_board_get_mii_address(ipd_port); 67262306a36Sopenharmony_ci octeon_fdt_set_phy(eth, phy_addr); 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci fixed_link = fdt_subnode_offset(initial_boot_params, eth, "fixed-link"); 67562306a36Sopenharmony_ci if (fixed_link < 0) 67662306a36Sopenharmony_ci WARN_ON(octeon_has_fixed_link(ipd_port)); 67762306a36Sopenharmony_ci else if (!octeon_has_fixed_link(ipd_port)) 67862306a36Sopenharmony_ci fdt_nop_node(initial_boot_params, fixed_link); 67962306a36Sopenharmony_ci octeon_rx_tx_delay(eth, i, p); 68062306a36Sopenharmony_ci} 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_cistatic void __init octeon_fdt_pip_iface(int pip, int idx) 68362306a36Sopenharmony_ci{ 68462306a36Sopenharmony_ci char name_buffer[20]; 68562306a36Sopenharmony_ci int iface; 68662306a36Sopenharmony_ci int p; 68762306a36Sopenharmony_ci int count = 0; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci snprintf(name_buffer, sizeof(name_buffer), "interface@%d", idx); 69062306a36Sopenharmony_ci iface = fdt_subnode_offset(initial_boot_params, pip, name_buffer); 69162306a36Sopenharmony_ci if (iface < 0) 69262306a36Sopenharmony_ci return; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci if (cvmx_helper_interface_enumerate(idx) == 0) 69562306a36Sopenharmony_ci count = cvmx_helper_ports_on_interface(idx); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci for (p = 0; p < 16; p++) 69862306a36Sopenharmony_ci octeon_fdt_pip_port(iface, idx, p, count - 1); 69962306a36Sopenharmony_ci} 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_civoid __init octeon_fill_mac_addresses(void) 70262306a36Sopenharmony_ci{ 70362306a36Sopenharmony_ci const char *alias_prop; 70462306a36Sopenharmony_ci char name_buffer[20]; 70562306a36Sopenharmony_ci u64 mac_addr_base; 70662306a36Sopenharmony_ci int aliases; 70762306a36Sopenharmony_ci int pip; 70862306a36Sopenharmony_ci int i; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci aliases = fdt_path_offset(initial_boot_params, "/aliases"); 71162306a36Sopenharmony_ci if (aliases < 0) 71262306a36Sopenharmony_ci return; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci mac_addr_base = 71562306a36Sopenharmony_ci ((octeon_bootinfo->mac_addr_base[0] & 0xffull)) << 40 | 71662306a36Sopenharmony_ci ((octeon_bootinfo->mac_addr_base[1] & 0xffull)) << 32 | 71762306a36Sopenharmony_ci ((octeon_bootinfo->mac_addr_base[2] & 0xffull)) << 24 | 71862306a36Sopenharmony_ci ((octeon_bootinfo->mac_addr_base[3] & 0xffull)) << 16 | 71962306a36Sopenharmony_ci ((octeon_bootinfo->mac_addr_base[4] & 0xffull)) << 8 | 72062306a36Sopenharmony_ci (octeon_bootinfo->mac_addr_base[5] & 0xffull); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 72362306a36Sopenharmony_ci int mgmt; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci snprintf(name_buffer, sizeof(name_buffer), "mix%d", i); 72662306a36Sopenharmony_ci alias_prop = fdt_getprop(initial_boot_params, aliases, 72762306a36Sopenharmony_ci name_buffer, NULL); 72862306a36Sopenharmony_ci if (!alias_prop) 72962306a36Sopenharmony_ci continue; 73062306a36Sopenharmony_ci mgmt = fdt_path_offset(initial_boot_params, alias_prop); 73162306a36Sopenharmony_ci if (mgmt < 0) 73262306a36Sopenharmony_ci continue; 73362306a36Sopenharmony_ci octeon_fdt_set_mac_addr(mgmt, &mac_addr_base); 73462306a36Sopenharmony_ci } 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci alias_prop = fdt_getprop(initial_boot_params, aliases, "pip", NULL); 73762306a36Sopenharmony_ci if (!alias_prop) 73862306a36Sopenharmony_ci return; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci pip = fdt_path_offset(initial_boot_params, alias_prop); 74162306a36Sopenharmony_ci if (pip < 0) 74262306a36Sopenharmony_ci return; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci for (i = 0; i <= 4; i++) { 74562306a36Sopenharmony_ci int iface; 74662306a36Sopenharmony_ci int p; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci snprintf(name_buffer, sizeof(name_buffer), "interface@%d", i); 74962306a36Sopenharmony_ci iface = fdt_subnode_offset(initial_boot_params, pip, 75062306a36Sopenharmony_ci name_buffer); 75162306a36Sopenharmony_ci if (iface < 0) 75262306a36Sopenharmony_ci continue; 75362306a36Sopenharmony_ci for (p = 0; p < 16; p++) { 75462306a36Sopenharmony_ci int eth; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci snprintf(name_buffer, sizeof(name_buffer), 75762306a36Sopenharmony_ci "ethernet@%x", p); 75862306a36Sopenharmony_ci eth = fdt_subnode_offset(initial_boot_params, iface, 75962306a36Sopenharmony_ci name_buffer); 76062306a36Sopenharmony_ci if (eth < 0) 76162306a36Sopenharmony_ci continue; 76262306a36Sopenharmony_ci octeon_fdt_set_mac_addr(eth, &mac_addr_base); 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci} 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ciint __init octeon_prune_device_tree(void) 76862306a36Sopenharmony_ci{ 76962306a36Sopenharmony_ci int i, max_port, uart_mask; 77062306a36Sopenharmony_ci const char *pip_path; 77162306a36Sopenharmony_ci const char *alias_prop; 77262306a36Sopenharmony_ci char name_buffer[20]; 77362306a36Sopenharmony_ci int aliases; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci if (fdt_check_header(initial_boot_params)) 77662306a36Sopenharmony_ci panic("Corrupt Device Tree."); 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci WARN(octeon_bootinfo->board_type == CVMX_BOARD_TYPE_CUST_DSR1000N, 77962306a36Sopenharmony_ci "Built-in DTB booting is deprecated on %s. Please switch to use appended DTB.", 78062306a36Sopenharmony_ci cvmx_board_type_to_string(octeon_bootinfo->board_type)); 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci aliases = fdt_path_offset(initial_boot_params, "/aliases"); 78362306a36Sopenharmony_ci if (aliases < 0) { 78462306a36Sopenharmony_ci pr_err("Error: No /aliases node in device tree."); 78562306a36Sopenharmony_ci return -EINVAL; 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN52XX) || OCTEON_IS_MODEL(OCTEON_CN63XX)) 78962306a36Sopenharmony_ci max_port = 2; 79062306a36Sopenharmony_ci else if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN68XX)) 79162306a36Sopenharmony_ci max_port = 1; 79262306a36Sopenharmony_ci else 79362306a36Sopenharmony_ci max_port = 0; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci if (octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC10E) 79662306a36Sopenharmony_ci max_port = 0; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 79962306a36Sopenharmony_ci int mgmt; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci snprintf(name_buffer, sizeof(name_buffer), 80262306a36Sopenharmony_ci "mix%d", i); 80362306a36Sopenharmony_ci alias_prop = fdt_getprop(initial_boot_params, aliases, 80462306a36Sopenharmony_ci name_buffer, NULL); 80562306a36Sopenharmony_ci if (alias_prop) { 80662306a36Sopenharmony_ci mgmt = fdt_path_offset(initial_boot_params, alias_prop); 80762306a36Sopenharmony_ci if (mgmt < 0) 80862306a36Sopenharmony_ci continue; 80962306a36Sopenharmony_ci if (i >= max_port) { 81062306a36Sopenharmony_ci pr_debug("Deleting mix%d\n", i); 81162306a36Sopenharmony_ci octeon_fdt_rm_ethernet(mgmt); 81262306a36Sopenharmony_ci fdt_nop_property(initial_boot_params, aliases, 81362306a36Sopenharmony_ci name_buffer); 81462306a36Sopenharmony_ci } else { 81562306a36Sopenharmony_ci int phy_addr = cvmx_helper_board_get_mii_address(CVMX_HELPER_BOARD_MGMT_IPD_PORT + i); 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci octeon_fdt_set_phy(mgmt, phy_addr); 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci } 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci pip_path = fdt_getprop(initial_boot_params, aliases, "pip", NULL); 82362306a36Sopenharmony_ci if (pip_path) { 82462306a36Sopenharmony_ci int pip = fdt_path_offset(initial_boot_params, pip_path); 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci if (pip >= 0) 82762306a36Sopenharmony_ci for (i = 0; i <= 4; i++) 82862306a36Sopenharmony_ci octeon_fdt_pip_iface(pip, i); 82962306a36Sopenharmony_ci } 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci /* I2C */ 83262306a36Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN52XX) || 83362306a36Sopenharmony_ci OCTEON_IS_MODEL(OCTEON_CN63XX) || 83462306a36Sopenharmony_ci OCTEON_IS_MODEL(OCTEON_CN68XX) || 83562306a36Sopenharmony_ci OCTEON_IS_MODEL(OCTEON_CN56XX)) 83662306a36Sopenharmony_ci max_port = 2; 83762306a36Sopenharmony_ci else 83862306a36Sopenharmony_ci max_port = 1; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 84162306a36Sopenharmony_ci int i2c; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci snprintf(name_buffer, sizeof(name_buffer), 84462306a36Sopenharmony_ci "twsi%d", i); 84562306a36Sopenharmony_ci alias_prop = fdt_getprop(initial_boot_params, aliases, 84662306a36Sopenharmony_ci name_buffer, NULL); 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci if (alias_prop) { 84962306a36Sopenharmony_ci i2c = fdt_path_offset(initial_boot_params, alias_prop); 85062306a36Sopenharmony_ci if (i2c < 0) 85162306a36Sopenharmony_ci continue; 85262306a36Sopenharmony_ci if (i >= max_port) { 85362306a36Sopenharmony_ci pr_debug("Deleting twsi%d\n", i); 85462306a36Sopenharmony_ci fdt_nop_node(initial_boot_params, i2c); 85562306a36Sopenharmony_ci fdt_nop_property(initial_boot_params, aliases, 85662306a36Sopenharmony_ci name_buffer); 85762306a36Sopenharmony_ci } 85862306a36Sopenharmony_ci } 85962306a36Sopenharmony_ci } 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci /* SMI/MDIO */ 86262306a36Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN68XX)) 86362306a36Sopenharmony_ci max_port = 4; 86462306a36Sopenharmony_ci else if (OCTEON_IS_MODEL(OCTEON_CN52XX) || 86562306a36Sopenharmony_ci OCTEON_IS_MODEL(OCTEON_CN63XX) || 86662306a36Sopenharmony_ci OCTEON_IS_MODEL(OCTEON_CN56XX)) 86762306a36Sopenharmony_ci max_port = 2; 86862306a36Sopenharmony_ci else 86962306a36Sopenharmony_ci max_port = 1; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 87262306a36Sopenharmony_ci int i2c; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci snprintf(name_buffer, sizeof(name_buffer), 87562306a36Sopenharmony_ci "smi%d", i); 87662306a36Sopenharmony_ci alias_prop = fdt_getprop(initial_boot_params, aliases, 87762306a36Sopenharmony_ci name_buffer, NULL); 87862306a36Sopenharmony_ci if (alias_prop) { 87962306a36Sopenharmony_ci i2c = fdt_path_offset(initial_boot_params, alias_prop); 88062306a36Sopenharmony_ci if (i2c < 0) 88162306a36Sopenharmony_ci continue; 88262306a36Sopenharmony_ci if (i >= max_port) { 88362306a36Sopenharmony_ci pr_debug("Deleting smi%d\n", i); 88462306a36Sopenharmony_ci fdt_nop_node(initial_boot_params, i2c); 88562306a36Sopenharmony_ci fdt_nop_property(initial_boot_params, aliases, 88662306a36Sopenharmony_ci name_buffer); 88762306a36Sopenharmony_ci } 88862306a36Sopenharmony_ci } 88962306a36Sopenharmony_ci } 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci /* Serial */ 89262306a36Sopenharmony_ci uart_mask = 3; 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci /* Right now CN52XX is the only chip with a third uart */ 89562306a36Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN52XX)) 89662306a36Sopenharmony_ci uart_mask |= 4; /* uart2 */ 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci for (i = 0; i < 3; i++) { 89962306a36Sopenharmony_ci int uart; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci snprintf(name_buffer, sizeof(name_buffer), 90262306a36Sopenharmony_ci "uart%d", i); 90362306a36Sopenharmony_ci alias_prop = fdt_getprop(initial_boot_params, aliases, 90462306a36Sopenharmony_ci name_buffer, NULL); 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci if (alias_prop) { 90762306a36Sopenharmony_ci uart = fdt_path_offset(initial_boot_params, alias_prop); 90862306a36Sopenharmony_ci if (uart_mask & (1 << i)) { 90962306a36Sopenharmony_ci __be32 f; 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci f = cpu_to_be32(octeon_get_io_clock_rate()); 91262306a36Sopenharmony_ci fdt_setprop_inplace(initial_boot_params, 91362306a36Sopenharmony_ci uart, "clock-frequency", 91462306a36Sopenharmony_ci &f, sizeof(f)); 91562306a36Sopenharmony_ci continue; 91662306a36Sopenharmony_ci } 91762306a36Sopenharmony_ci pr_debug("Deleting uart%d\n", i); 91862306a36Sopenharmony_ci fdt_nop_node(initial_boot_params, uart); 91962306a36Sopenharmony_ci fdt_nop_property(initial_boot_params, aliases, 92062306a36Sopenharmony_ci name_buffer); 92162306a36Sopenharmony_ci } 92262306a36Sopenharmony_ci } 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci /* Compact Flash */ 92562306a36Sopenharmony_ci alias_prop = fdt_getprop(initial_boot_params, aliases, 92662306a36Sopenharmony_ci "cf0", NULL); 92762306a36Sopenharmony_ci if (alias_prop) { 92862306a36Sopenharmony_ci union cvmx_mio_boot_reg_cfgx mio_boot_reg_cfg; 92962306a36Sopenharmony_ci unsigned long base_ptr, region_base, region_size; 93062306a36Sopenharmony_ci unsigned long region1_base = 0; 93162306a36Sopenharmony_ci unsigned long region1_size = 0; 93262306a36Sopenharmony_ci int cs, bootbus; 93362306a36Sopenharmony_ci bool is_16bit = false; 93462306a36Sopenharmony_ci bool is_true_ide = false; 93562306a36Sopenharmony_ci __be32 new_reg[6]; 93662306a36Sopenharmony_ci __be32 *ranges; 93762306a36Sopenharmony_ci int len; 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci int cf = fdt_path_offset(initial_boot_params, alias_prop); 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci base_ptr = 0; 94262306a36Sopenharmony_ci if (octeon_bootinfo->major_version == 1 94362306a36Sopenharmony_ci && octeon_bootinfo->minor_version >= 1) { 94462306a36Sopenharmony_ci if (octeon_bootinfo->compact_flash_common_base_addr) 94562306a36Sopenharmony_ci base_ptr = octeon_bootinfo->compact_flash_common_base_addr; 94662306a36Sopenharmony_ci } else { 94762306a36Sopenharmony_ci base_ptr = 0x1d000800; 94862306a36Sopenharmony_ci } 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci if (!base_ptr) 95162306a36Sopenharmony_ci goto no_cf; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci /* Find CS0 region. */ 95462306a36Sopenharmony_ci for (cs = 0; cs < 8; cs++) { 95562306a36Sopenharmony_ci mio_boot_reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs)); 95662306a36Sopenharmony_ci region_base = mio_boot_reg_cfg.s.base << 16; 95762306a36Sopenharmony_ci region_size = (mio_boot_reg_cfg.s.size + 1) << 16; 95862306a36Sopenharmony_ci if (mio_boot_reg_cfg.s.en && base_ptr >= region_base 95962306a36Sopenharmony_ci && base_ptr < region_base + region_size) { 96062306a36Sopenharmony_ci is_16bit = mio_boot_reg_cfg.s.width; 96162306a36Sopenharmony_ci break; 96262306a36Sopenharmony_ci } 96362306a36Sopenharmony_ci } 96462306a36Sopenharmony_ci if (cs >= 7) { 96562306a36Sopenharmony_ci /* cs and cs + 1 are CS0 and CS1, both must be less than 8. */ 96662306a36Sopenharmony_ci goto no_cf; 96762306a36Sopenharmony_ci } 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci if (!(base_ptr & 0xfffful)) { 97062306a36Sopenharmony_ci /* 97162306a36Sopenharmony_ci * Boot loader signals availability of DMA (true_ide 97262306a36Sopenharmony_ci * mode) by setting low order bits of base_ptr to 97362306a36Sopenharmony_ci * zero. 97462306a36Sopenharmony_ci */ 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci /* Asume that CS1 immediately follows. */ 97762306a36Sopenharmony_ci mio_boot_reg_cfg.u64 = 97862306a36Sopenharmony_ci cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs + 1)); 97962306a36Sopenharmony_ci region1_base = mio_boot_reg_cfg.s.base << 16; 98062306a36Sopenharmony_ci region1_size = (mio_boot_reg_cfg.s.size + 1) << 16; 98162306a36Sopenharmony_ci if (!mio_boot_reg_cfg.s.en) 98262306a36Sopenharmony_ci goto no_cf; 98362306a36Sopenharmony_ci is_true_ide = true; 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci } else { 98662306a36Sopenharmony_ci fdt_nop_property(initial_boot_params, cf, "cavium,true-ide"); 98762306a36Sopenharmony_ci fdt_nop_property(initial_boot_params, cf, "cavium,dma-engine-handle"); 98862306a36Sopenharmony_ci if (!is_16bit) { 98962306a36Sopenharmony_ci __be32 width = cpu_to_be32(8); 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci fdt_setprop_inplace(initial_boot_params, cf, 99262306a36Sopenharmony_ci "cavium,bus-width", &width, sizeof(width)); 99362306a36Sopenharmony_ci } 99462306a36Sopenharmony_ci } 99562306a36Sopenharmony_ci new_reg[0] = cpu_to_be32(cs); 99662306a36Sopenharmony_ci new_reg[1] = cpu_to_be32(0); 99762306a36Sopenharmony_ci new_reg[2] = cpu_to_be32(0x10000); 99862306a36Sopenharmony_ci new_reg[3] = cpu_to_be32(cs + 1); 99962306a36Sopenharmony_ci new_reg[4] = cpu_to_be32(0); 100062306a36Sopenharmony_ci new_reg[5] = cpu_to_be32(0x10000); 100162306a36Sopenharmony_ci fdt_setprop_inplace(initial_boot_params, cf, 100262306a36Sopenharmony_ci "reg", new_reg, sizeof(new_reg)); 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci bootbus = fdt_parent_offset(initial_boot_params, cf); 100562306a36Sopenharmony_ci if (bootbus < 0) 100662306a36Sopenharmony_ci goto no_cf; 100762306a36Sopenharmony_ci ranges = fdt_getprop_w(initial_boot_params, bootbus, "ranges", &len); 100862306a36Sopenharmony_ci if (!ranges || len < (5 * 8 * sizeof(__be32))) 100962306a36Sopenharmony_ci goto no_cf; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci ranges[(cs * 5) + 2] = cpu_to_be32(region_base >> 32); 101262306a36Sopenharmony_ci ranges[(cs * 5) + 3] = cpu_to_be32(region_base & 0xffffffff); 101362306a36Sopenharmony_ci ranges[(cs * 5) + 4] = cpu_to_be32(region_size); 101462306a36Sopenharmony_ci if (is_true_ide) { 101562306a36Sopenharmony_ci cs++; 101662306a36Sopenharmony_ci ranges[(cs * 5) + 2] = cpu_to_be32(region1_base >> 32); 101762306a36Sopenharmony_ci ranges[(cs * 5) + 3] = cpu_to_be32(region1_base & 0xffffffff); 101862306a36Sopenharmony_ci ranges[(cs * 5) + 4] = cpu_to_be32(region1_size); 101962306a36Sopenharmony_ci } 102062306a36Sopenharmony_ci goto end_cf; 102162306a36Sopenharmony_cino_cf: 102262306a36Sopenharmony_ci fdt_nop_node(initial_boot_params, cf); 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ciend_cf: 102562306a36Sopenharmony_ci ; 102662306a36Sopenharmony_ci } 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci /* 8 char LED */ 102962306a36Sopenharmony_ci alias_prop = fdt_getprop(initial_boot_params, aliases, 103062306a36Sopenharmony_ci "led0", NULL); 103162306a36Sopenharmony_ci if (alias_prop) { 103262306a36Sopenharmony_ci union cvmx_mio_boot_reg_cfgx mio_boot_reg_cfg; 103362306a36Sopenharmony_ci unsigned long base_ptr, region_base, region_size; 103462306a36Sopenharmony_ci int cs, bootbus; 103562306a36Sopenharmony_ci __be32 new_reg[6]; 103662306a36Sopenharmony_ci __be32 *ranges; 103762306a36Sopenharmony_ci int len; 103862306a36Sopenharmony_ci int led = fdt_path_offset(initial_boot_params, alias_prop); 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci base_ptr = octeon_bootinfo->led_display_base_addr; 104162306a36Sopenharmony_ci if (base_ptr == 0) 104262306a36Sopenharmony_ci goto no_led; 104362306a36Sopenharmony_ci /* Find CS0 region. */ 104462306a36Sopenharmony_ci for (cs = 0; cs < 8; cs++) { 104562306a36Sopenharmony_ci mio_boot_reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs)); 104662306a36Sopenharmony_ci region_base = mio_boot_reg_cfg.s.base << 16; 104762306a36Sopenharmony_ci region_size = (mio_boot_reg_cfg.s.size + 1) << 16; 104862306a36Sopenharmony_ci if (mio_boot_reg_cfg.s.en && base_ptr >= region_base 104962306a36Sopenharmony_ci && base_ptr < region_base + region_size) 105062306a36Sopenharmony_ci break; 105162306a36Sopenharmony_ci } 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci if (cs > 7) 105462306a36Sopenharmony_ci goto no_led; 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci new_reg[0] = cpu_to_be32(cs); 105762306a36Sopenharmony_ci new_reg[1] = cpu_to_be32(0x20); 105862306a36Sopenharmony_ci new_reg[2] = cpu_to_be32(0x20); 105962306a36Sopenharmony_ci new_reg[3] = cpu_to_be32(cs); 106062306a36Sopenharmony_ci new_reg[4] = cpu_to_be32(0); 106162306a36Sopenharmony_ci new_reg[5] = cpu_to_be32(0x20); 106262306a36Sopenharmony_ci fdt_setprop_inplace(initial_boot_params, led, 106362306a36Sopenharmony_ci "reg", new_reg, sizeof(new_reg)); 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci bootbus = fdt_parent_offset(initial_boot_params, led); 106662306a36Sopenharmony_ci if (bootbus < 0) 106762306a36Sopenharmony_ci goto no_led; 106862306a36Sopenharmony_ci ranges = fdt_getprop_w(initial_boot_params, bootbus, "ranges", &len); 106962306a36Sopenharmony_ci if (!ranges || len < (5 * 8 * sizeof(__be32))) 107062306a36Sopenharmony_ci goto no_led; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci ranges[(cs * 5) + 2] = cpu_to_be32(region_base >> 32); 107362306a36Sopenharmony_ci ranges[(cs * 5) + 3] = cpu_to_be32(region_base & 0xffffffff); 107462306a36Sopenharmony_ci ranges[(cs * 5) + 4] = cpu_to_be32(region_size); 107562306a36Sopenharmony_ci goto end_led; 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_cino_led: 107862306a36Sopenharmony_ci fdt_nop_node(initial_boot_params, led); 107962306a36Sopenharmony_ciend_led: 108062306a36Sopenharmony_ci ; 108162306a36Sopenharmony_ci } 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci#ifdef CONFIG_USB 108462306a36Sopenharmony_ci /* OHCI/UHCI USB */ 108562306a36Sopenharmony_ci alias_prop = fdt_getprop(initial_boot_params, aliases, 108662306a36Sopenharmony_ci "uctl", NULL); 108762306a36Sopenharmony_ci if (alias_prop) { 108862306a36Sopenharmony_ci int uctl = fdt_path_offset(initial_boot_params, alias_prop); 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci if (uctl >= 0 && (!OCTEON_IS_MODEL(OCTEON_CN6XXX) || 109162306a36Sopenharmony_ci octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC2E)) { 109262306a36Sopenharmony_ci pr_debug("Deleting uctl\n"); 109362306a36Sopenharmony_ci fdt_nop_node(initial_boot_params, uctl); 109462306a36Sopenharmony_ci fdt_nop_property(initial_boot_params, aliases, "uctl"); 109562306a36Sopenharmony_ci } else if (octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC10E || 109662306a36Sopenharmony_ci octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC4E) { 109762306a36Sopenharmony_ci /* Missing "refclk-type" defaults to crystal. */ 109862306a36Sopenharmony_ci fdt_nop_property(initial_boot_params, uctl, "refclk-type"); 109962306a36Sopenharmony_ci } 110062306a36Sopenharmony_ci } 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci /* DWC2 USB */ 110362306a36Sopenharmony_ci alias_prop = fdt_getprop(initial_boot_params, aliases, 110462306a36Sopenharmony_ci "usbn", NULL); 110562306a36Sopenharmony_ci if (alias_prop) { 110662306a36Sopenharmony_ci int usbn = fdt_path_offset(initial_boot_params, alias_prop); 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci if (usbn >= 0 && (current_cpu_type() == CPU_CAVIUM_OCTEON2 || 110962306a36Sopenharmony_ci !octeon_has_feature(OCTEON_FEATURE_USB))) { 111062306a36Sopenharmony_ci pr_debug("Deleting usbn\n"); 111162306a36Sopenharmony_ci fdt_nop_node(initial_boot_params, usbn); 111262306a36Sopenharmony_ci fdt_nop_property(initial_boot_params, aliases, "usbn"); 111362306a36Sopenharmony_ci } else { 111462306a36Sopenharmony_ci __be32 new_f[1]; 111562306a36Sopenharmony_ci enum cvmx_helper_board_usb_clock_types c; 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci c = __cvmx_helper_board_usb_get_clock_type(); 111862306a36Sopenharmony_ci switch (c) { 111962306a36Sopenharmony_ci case USB_CLOCK_TYPE_REF_48: 112062306a36Sopenharmony_ci new_f[0] = cpu_to_be32(48000000); 112162306a36Sopenharmony_ci fdt_setprop_inplace(initial_boot_params, usbn, 112262306a36Sopenharmony_ci "refclk-frequency", new_f, sizeof(new_f)); 112362306a36Sopenharmony_ci fallthrough; 112462306a36Sopenharmony_ci case USB_CLOCK_TYPE_REF_12: 112562306a36Sopenharmony_ci /* Missing "refclk-type" defaults to external. */ 112662306a36Sopenharmony_ci fdt_nop_property(initial_boot_params, usbn, "refclk-type"); 112762306a36Sopenharmony_ci break; 112862306a36Sopenharmony_ci default: 112962306a36Sopenharmony_ci break; 113062306a36Sopenharmony_ci } 113162306a36Sopenharmony_ci } 113262306a36Sopenharmony_ci } 113362306a36Sopenharmony_ci#endif 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci return 0; 113662306a36Sopenharmony_ci} 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_cistatic int __init octeon_publish_devices(void) 113962306a36Sopenharmony_ci{ 114062306a36Sopenharmony_ci return of_platform_populate(NULL, octeon_ids, NULL, NULL); 114162306a36Sopenharmony_ci} 114262306a36Sopenharmony_ciarch_initcall(octeon_publish_devices); 1143