18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * XHCI HCD glue for Cavium Octeon III SOCs.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2010-2017 Cavium Networks
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
78c2ecf20Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
88c2ecf20Sopenharmony_ci * for more details.
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci#include <linux/device.h>
138c2ecf20Sopenharmony_ci#include <linux/mutex.h>
148c2ecf20Sopenharmony_ci#include <linux/delay.h>
158c2ecf20Sopenharmony_ci#include <linux/of_platform.h>
168c2ecf20Sopenharmony_ci#include <linux/io.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <asm/octeon/octeon.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci/* USB Control Register */
218c2ecf20Sopenharmony_ciunion cvm_usbdrd_uctl_ctl {
228c2ecf20Sopenharmony_ci	uint64_t u64;
238c2ecf20Sopenharmony_ci	struct cvm_usbdrd_uctl_ctl_s {
248c2ecf20Sopenharmony_ci	/* 1 = BIST and set all USB RAMs to 0x0, 0 = BIST */
258c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t clear_bist:1,
268c2ecf20Sopenharmony_ci	/* 1 = Start BIST and cleared by hardware */
278c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t start_bist:1,
288c2ecf20Sopenharmony_ci	/* Reference clock select for SuperSpeed and HighSpeed PLLs:
298c2ecf20Sopenharmony_ci	 *	0x0 = Both PLLs use DLMC_REF_CLK0 for reference clock
308c2ecf20Sopenharmony_ci	 *	0x1 = Both PLLs use DLMC_REF_CLK1 for reference clock
318c2ecf20Sopenharmony_ci	 *	0x2 = SuperSpeed PLL uses DLMC_REF_CLK0 for reference clock &
328c2ecf20Sopenharmony_ci	 *	      HighSpeed PLL uses PLL_REF_CLK for reference clck
338c2ecf20Sopenharmony_ci	 *	0x3 = SuperSpeed PLL uses DLMC_REF_CLK1 for reference clock &
348c2ecf20Sopenharmony_ci	 *	      HighSpeed PLL uses PLL_REF_CLK for reference clck
358c2ecf20Sopenharmony_ci	 */
368c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t ref_clk_sel:2,
378c2ecf20Sopenharmony_ci	/* 1 = Spread-spectrum clock enable, 0 = SS clock disable */
388c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t ssc_en:1,
398c2ecf20Sopenharmony_ci	/* Spread-spectrum clock modulation range:
408c2ecf20Sopenharmony_ci	 *	0x0 = -4980 ppm downspread
418c2ecf20Sopenharmony_ci	 *	0x1 = -4492 ppm downspread
428c2ecf20Sopenharmony_ci	 *	0x2 = -4003 ppm downspread
438c2ecf20Sopenharmony_ci	 *	0x3 - 0x7 = Reserved
448c2ecf20Sopenharmony_ci	 */
458c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t ssc_range:3,
468c2ecf20Sopenharmony_ci	/* Enable non-standard oscillator frequencies:
478c2ecf20Sopenharmony_ci	 *	[55:53] = modules -1
488c2ecf20Sopenharmony_ci	 *	[52:47] = 2's complement push amount, 0 = Feature disabled
498c2ecf20Sopenharmony_ci	 */
508c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t ssc_ref_clk_sel:9,
518c2ecf20Sopenharmony_ci	/* Reference clock multiplier for non-standard frequencies:
528c2ecf20Sopenharmony_ci	 *	0x19 = 100MHz on DLMC_REF_CLK* if REF_CLK_SEL = 0x0 or 0x1
538c2ecf20Sopenharmony_ci	 *	0x28 = 125MHz on DLMC_REF_CLK* if REF_CLK_SEL = 0x0 or 0x1
548c2ecf20Sopenharmony_ci	 *	0x32 =  50MHz on DLMC_REF_CLK* if REF_CLK_SEL = 0x0 or 0x1
558c2ecf20Sopenharmony_ci	 *	Other Values = Reserved
568c2ecf20Sopenharmony_ci	 */
578c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t mpll_multiplier:7,
588c2ecf20Sopenharmony_ci	/* Enable reference clock to prescaler for SuperSpeed functionality.
598c2ecf20Sopenharmony_ci	 * Should always be set to "1"
608c2ecf20Sopenharmony_ci	 */
618c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t ref_ssp_en:1,
628c2ecf20Sopenharmony_ci	/* Divide the reference clock by 2 before entering the
638c2ecf20Sopenharmony_ci	 * REF_CLK_FSEL divider:
648c2ecf20Sopenharmony_ci	 *	If REF_CLK_SEL = 0x0 or 0x1, then only 0x0 is legal
658c2ecf20Sopenharmony_ci	 *	If REF_CLK_SEL = 0x2 or 0x3, then:
668c2ecf20Sopenharmony_ci	 *		0x1 = DLMC_REF_CLK* is 125MHz
678c2ecf20Sopenharmony_ci	 *		0x0 = DLMC_REF_CLK* is another supported frequency
688c2ecf20Sopenharmony_ci	 */
698c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t ref_clk_div2:1,
708c2ecf20Sopenharmony_ci	/* Select reference clock freqnuency for both PLL blocks:
718c2ecf20Sopenharmony_ci	 *	0x27 = REF_CLK_SEL is 0x0 or 0x1
728c2ecf20Sopenharmony_ci	 *	0x07 = REF_CLK_SEL is 0x2 or 0x3
738c2ecf20Sopenharmony_ci	 */
748c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t ref_clk_fsel:6,
758c2ecf20Sopenharmony_ci	/* Reserved */
768c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t reserved_31_31:1,
778c2ecf20Sopenharmony_ci	/* Controller clock enable. */
788c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t h_clk_en:1,
798c2ecf20Sopenharmony_ci	/* Select bypass input to controller clock divider:
808c2ecf20Sopenharmony_ci	 *	0x0 = Use divided coprocessor clock from H_CLKDIV
818c2ecf20Sopenharmony_ci	 *	0x1 = Use clock from GPIO pins
828c2ecf20Sopenharmony_ci	 */
838c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t h_clk_byp_sel:1,
848c2ecf20Sopenharmony_ci	/* Reset controller clock divider. */
858c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t h_clkdiv_rst:1,
868c2ecf20Sopenharmony_ci	/* Reserved */
878c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t reserved_27_27:1,
888c2ecf20Sopenharmony_ci	/* Clock divider select:
898c2ecf20Sopenharmony_ci	 *	0x0 = divide by 1
908c2ecf20Sopenharmony_ci	 *	0x1 = divide by 2
918c2ecf20Sopenharmony_ci	 *	0x2 = divide by 4
928c2ecf20Sopenharmony_ci	 *	0x3 = divide by 6
938c2ecf20Sopenharmony_ci	 *	0x4 = divide by 8
948c2ecf20Sopenharmony_ci	 *	0x5 = divide by 16
958c2ecf20Sopenharmony_ci	 *	0x6 = divide by 24
968c2ecf20Sopenharmony_ci	 *	0x7 = divide by 32
978c2ecf20Sopenharmony_ci	 */
988c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t h_clkdiv_sel:3,
998c2ecf20Sopenharmony_ci	/* Reserved */
1008c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t reserved_22_23:2,
1018c2ecf20Sopenharmony_ci	/* USB3 port permanently attached: 0x0 = No, 0x1 = Yes */
1028c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t usb3_port_perm_attach:1,
1038c2ecf20Sopenharmony_ci	/* USB2 port permanently attached: 0x0 = No, 0x1 = Yes */
1048c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t usb2_port_perm_attach:1,
1058c2ecf20Sopenharmony_ci	/* Reserved */
1068c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t reserved_19_19:1,
1078c2ecf20Sopenharmony_ci	/* Disable SuperSpeed PHY: 0x0 = No, 0x1 = Yes */
1088c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t usb3_port_disable:1,
1098c2ecf20Sopenharmony_ci	/* Reserved */
1108c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t reserved_17_17:1,
1118c2ecf20Sopenharmony_ci	/* Disable HighSpeed PHY: 0x0 = No, 0x1 = Yes */
1128c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t usb2_port_disable:1,
1138c2ecf20Sopenharmony_ci	/* Reserved */
1148c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t reserved_15_15:1,
1158c2ecf20Sopenharmony_ci	/* Enable PHY SuperSpeed block power: 0x0 = No, 0x1 = Yes */
1168c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t ss_power_en:1,
1178c2ecf20Sopenharmony_ci	/* Reserved */
1188c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t reserved_13_13:1,
1198c2ecf20Sopenharmony_ci	/* Enable PHY HighSpeed block power: 0x0 = No, 0x1 = Yes */
1208c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t hs_power_en:1,
1218c2ecf20Sopenharmony_ci	/* Reserved */
1228c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t reserved_5_11:7,
1238c2ecf20Sopenharmony_ci	/* Enable USB UCTL interface clock: 0xx = No, 0x1 = Yes */
1248c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t csclk_en:1,
1258c2ecf20Sopenharmony_ci	/* Controller mode: 0x0 = Host, 0x1 = Device */
1268c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t drd_mode:1,
1278c2ecf20Sopenharmony_ci	/* PHY reset */
1288c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t uphy_rst:1,
1298c2ecf20Sopenharmony_ci	/* Software reset UAHC */
1308c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t uahc_rst:1,
1318c2ecf20Sopenharmony_ci	/* Software resets UCTL */
1328c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t uctl_rst:1,
1338c2ecf20Sopenharmony_ci	;)))))))))))))))))))))))))))))))))
1348c2ecf20Sopenharmony_ci	} s;
1358c2ecf20Sopenharmony_ci};
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci/* UAHC Configuration Register */
1388c2ecf20Sopenharmony_ciunion cvm_usbdrd_uctl_host_cfg {
1398c2ecf20Sopenharmony_ci	uint64_t u64;
1408c2ecf20Sopenharmony_ci	struct cvm_usbdrd_uctl_host_cfg_s {
1418c2ecf20Sopenharmony_ci	/* Reserved */
1428c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t reserved_60_63:4,
1438c2ecf20Sopenharmony_ci	/* Indicates minimum value of all received BELT values */
1448c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t host_current_belt:12,
1458c2ecf20Sopenharmony_ci	/* Reserved */
1468c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t reserved_38_47:10,
1478c2ecf20Sopenharmony_ci	/* HS jitter adjustment */
1488c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t fla:6,
1498c2ecf20Sopenharmony_ci	/* Reserved */
1508c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t reserved_29_31:3,
1518c2ecf20Sopenharmony_ci	/* Bus-master enable: 0x0 = Disabled (stall DMAs), 0x1 = enabled */
1528c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t bme:1,
1538c2ecf20Sopenharmony_ci	/* Overcurrent protection enable: 0x0 = unavailable, 0x1 = available */
1548c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t oci_en:1,
1558c2ecf20Sopenharmony_ci	/* Overcurrent sene selection:
1568c2ecf20Sopenharmony_ci	 *	0x0 = Overcurrent indication from off-chip is active-low
1578c2ecf20Sopenharmony_ci	 *	0x1 = Overcurrent indication from off-chip is active-high
1588c2ecf20Sopenharmony_ci	 */
1598c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t oci_active_high_en:1,
1608c2ecf20Sopenharmony_ci	/* Port power control enable: 0x0 = unavailable, 0x1 = available */
1618c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t ppc_en:1,
1628c2ecf20Sopenharmony_ci	/* Port power control sense selection:
1638c2ecf20Sopenharmony_ci	 *	0x0 = Port power to off-chip is active-low
1648c2ecf20Sopenharmony_ci	 *	0x1 = Port power to off-chip is active-high
1658c2ecf20Sopenharmony_ci	 */
1668c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t ppc_active_high_en:1,
1678c2ecf20Sopenharmony_ci	/* Reserved */
1688c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t reserved_0_23:24,
1698c2ecf20Sopenharmony_ci	;)))))))))))
1708c2ecf20Sopenharmony_ci	} s;
1718c2ecf20Sopenharmony_ci};
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci/* UCTL Shim Features Register */
1748c2ecf20Sopenharmony_ciunion cvm_usbdrd_uctl_shim_cfg {
1758c2ecf20Sopenharmony_ci	uint64_t u64;
1768c2ecf20Sopenharmony_ci	struct cvm_usbdrd_uctl_shim_cfg_s {
1778c2ecf20Sopenharmony_ci	/* Out-of-bound UAHC register access: 0 = read, 1 = write */
1788c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t xs_ncb_oob_wrn:1,
1798c2ecf20Sopenharmony_ci	/* Reserved */
1808c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t reserved_60_62:3,
1818c2ecf20Sopenharmony_ci	/* SRCID error log for out-of-bound UAHC register access:
1828c2ecf20Sopenharmony_ci	 *	[59:58] = chipID
1838c2ecf20Sopenharmony_ci	 *	[57] = Request source: 0 = core, 1 = NCB-device
1848c2ecf20Sopenharmony_ci	 *	[56:51] = Core/NCB-device number, [56] always 0 for NCB devices
1858c2ecf20Sopenharmony_ci	 *	[50:48] = SubID
1868c2ecf20Sopenharmony_ci	 */
1878c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t xs_ncb_oob_osrc:12,
1888c2ecf20Sopenharmony_ci	/* Error log for bad UAHC DMA access: 0 = Read log, 1 = Write log */
1898c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t xm_bad_dma_wrn:1,
1908c2ecf20Sopenharmony_ci	/* Reserved */
1918c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t reserved_44_46:3,
1928c2ecf20Sopenharmony_ci	/* Encoded error type for bad UAHC DMA */
1938c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t xm_bad_dma_type:4,
1948c2ecf20Sopenharmony_ci	/* Reserved */
1958c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t reserved_13_39:27,
1968c2ecf20Sopenharmony_ci	/* Select the IOI read command used by DMA accesses */
1978c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t dma_read_cmd:1,
1988c2ecf20Sopenharmony_ci	/* Reserved */
1998c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t reserved_10_11:2,
2008c2ecf20Sopenharmony_ci	/* Select endian format for DMA accesses to the L2c:
2018c2ecf20Sopenharmony_ci	 *	0x0 = Little endian
2028c2ecf20Sopenharmony_ci	 *`	0x1 = Big endian
2038c2ecf20Sopenharmony_ci	 *	0x2 = Reserved
2048c2ecf20Sopenharmony_ci	 *	0x3 = Reserved
2058c2ecf20Sopenharmony_ci	 */
2068c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t dma_endian_mode:2,
2078c2ecf20Sopenharmony_ci	/* Reserved */
2088c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t reserved_2_7:6,
2098c2ecf20Sopenharmony_ci	/* Select endian format for IOI CSR access to UAHC:
2108c2ecf20Sopenharmony_ci	 *	0x0 = Little endian
2118c2ecf20Sopenharmony_ci	 *`	0x1 = Big endian
2128c2ecf20Sopenharmony_ci	 *	0x2 = Reserved
2138c2ecf20Sopenharmony_ci	 *	0x3 = Reserved
2148c2ecf20Sopenharmony_ci	 */
2158c2ecf20Sopenharmony_ci	__BITFIELD_FIELD(uint64_t csr_endian_mode:2,
2168c2ecf20Sopenharmony_ci	;))))))))))))
2178c2ecf20Sopenharmony_ci	} s;
2188c2ecf20Sopenharmony_ci};
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci#define OCTEON_H_CLKDIV_SEL		8
2218c2ecf20Sopenharmony_ci#define OCTEON_MIN_H_CLK_RATE		150000000
2228c2ecf20Sopenharmony_ci#define OCTEON_MAX_H_CLK_RATE		300000000
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(dwc3_octeon_clocks_mutex);
2258c2ecf20Sopenharmony_cistatic uint8_t clk_div[OCTEON_H_CLKDIV_SEL] = {1, 2, 4, 6, 8, 16, 24, 32};
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_cistatic int dwc3_octeon_config_power(struct device *dev, u64 base)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci#define UCTL_HOST_CFG	0xe0
2318c2ecf20Sopenharmony_ci	union cvm_usbdrd_uctl_host_cfg uctl_host_cfg;
2328c2ecf20Sopenharmony_ci	union cvmx_gpio_bit_cfgx gpio_bit;
2338c2ecf20Sopenharmony_ci	uint32_t gpio_pwr[3];
2348c2ecf20Sopenharmony_ci	int gpio, len, power_active_low;
2358c2ecf20Sopenharmony_ci	struct device_node *node = dev->of_node;
2368c2ecf20Sopenharmony_ci	int index = (base >> 24) & 1;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	if (of_find_property(node, "power", &len) != NULL) {
2398c2ecf20Sopenharmony_ci		if (len == 12) {
2408c2ecf20Sopenharmony_ci			of_property_read_u32_array(node, "power", gpio_pwr, 3);
2418c2ecf20Sopenharmony_ci			power_active_low = gpio_pwr[2] & 0x01;
2428c2ecf20Sopenharmony_ci			gpio = gpio_pwr[1];
2438c2ecf20Sopenharmony_ci		} else if (len == 8) {
2448c2ecf20Sopenharmony_ci			of_property_read_u32_array(node, "power", gpio_pwr, 2);
2458c2ecf20Sopenharmony_ci			power_active_low = 0;
2468c2ecf20Sopenharmony_ci			gpio = gpio_pwr[1];
2478c2ecf20Sopenharmony_ci		} else {
2488c2ecf20Sopenharmony_ci			dev_err(dev, "dwc3 controller clock init failure.\n");
2498c2ecf20Sopenharmony_ci			return -EINVAL;
2508c2ecf20Sopenharmony_ci		}
2518c2ecf20Sopenharmony_ci		if ((OCTEON_IS_MODEL(OCTEON_CN73XX) ||
2528c2ecf20Sopenharmony_ci		    OCTEON_IS_MODEL(OCTEON_CNF75XX))
2538c2ecf20Sopenharmony_ci		    && gpio <= 31) {
2548c2ecf20Sopenharmony_ci			gpio_bit.u64 = cvmx_read_csr(CVMX_GPIO_BIT_CFGX(gpio));
2558c2ecf20Sopenharmony_ci			gpio_bit.s.tx_oe = 1;
2568c2ecf20Sopenharmony_ci			gpio_bit.s.output_sel = (index == 0 ? 0x14 : 0x15);
2578c2ecf20Sopenharmony_ci			cvmx_write_csr(CVMX_GPIO_BIT_CFGX(gpio), gpio_bit.u64);
2588c2ecf20Sopenharmony_ci		} else if (gpio <= 15) {
2598c2ecf20Sopenharmony_ci			gpio_bit.u64 = cvmx_read_csr(CVMX_GPIO_BIT_CFGX(gpio));
2608c2ecf20Sopenharmony_ci			gpio_bit.s.tx_oe = 1;
2618c2ecf20Sopenharmony_ci			gpio_bit.s.output_sel = (index == 0 ? 0x14 : 0x19);
2628c2ecf20Sopenharmony_ci			cvmx_write_csr(CVMX_GPIO_BIT_CFGX(gpio), gpio_bit.u64);
2638c2ecf20Sopenharmony_ci		} else {
2648c2ecf20Sopenharmony_ci			gpio_bit.u64 = cvmx_read_csr(CVMX_GPIO_XBIT_CFGX(gpio));
2658c2ecf20Sopenharmony_ci			gpio_bit.s.tx_oe = 1;
2668c2ecf20Sopenharmony_ci			gpio_bit.s.output_sel = (index == 0 ? 0x14 : 0x19);
2678c2ecf20Sopenharmony_ci			cvmx_write_csr(CVMX_GPIO_XBIT_CFGX(gpio), gpio_bit.u64);
2688c2ecf20Sopenharmony_ci		}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci		/* Enable XHCI power control and set if active high or low. */
2718c2ecf20Sopenharmony_ci		uctl_host_cfg.u64 = cvmx_read_csr(base + UCTL_HOST_CFG);
2728c2ecf20Sopenharmony_ci		uctl_host_cfg.s.ppc_en = 1;
2738c2ecf20Sopenharmony_ci		uctl_host_cfg.s.ppc_active_high_en = !power_active_low;
2748c2ecf20Sopenharmony_ci		cvmx_write_csr(base + UCTL_HOST_CFG, uctl_host_cfg.u64);
2758c2ecf20Sopenharmony_ci	} else {
2768c2ecf20Sopenharmony_ci		/* Disable XHCI power control and set if active high. */
2778c2ecf20Sopenharmony_ci		uctl_host_cfg.u64 = cvmx_read_csr(base + UCTL_HOST_CFG);
2788c2ecf20Sopenharmony_ci		uctl_host_cfg.s.ppc_en = 0;
2798c2ecf20Sopenharmony_ci		uctl_host_cfg.s.ppc_active_high_en = 0;
2808c2ecf20Sopenharmony_ci		cvmx_write_csr(base + UCTL_HOST_CFG, uctl_host_cfg.u64);
2818c2ecf20Sopenharmony_ci		dev_warn(dev, "dwc3 controller clock init failure.\n");
2828c2ecf20Sopenharmony_ci	}
2838c2ecf20Sopenharmony_ci	return 0;
2848c2ecf20Sopenharmony_ci}
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_cistatic int dwc3_octeon_clocks_start(struct device *dev, u64 base)
2878c2ecf20Sopenharmony_ci{
2888c2ecf20Sopenharmony_ci	union cvm_usbdrd_uctl_ctl uctl_ctl;
2898c2ecf20Sopenharmony_ci	int ref_clk_sel = 2;
2908c2ecf20Sopenharmony_ci	u64 div;
2918c2ecf20Sopenharmony_ci	u32 clock_rate;
2928c2ecf20Sopenharmony_ci	int mpll_mul;
2938c2ecf20Sopenharmony_ci	int i;
2948c2ecf20Sopenharmony_ci	u64 h_clk_rate;
2958c2ecf20Sopenharmony_ci	u64 uctl_ctl_reg = base;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	if (dev->of_node) {
2988c2ecf20Sopenharmony_ci		const char *ss_clock_type;
2998c2ecf20Sopenharmony_ci		const char *hs_clock_type;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci		i = of_property_read_u32(dev->of_node,
3028c2ecf20Sopenharmony_ci					 "refclk-frequency", &clock_rate);
3038c2ecf20Sopenharmony_ci		if (i) {
3048c2ecf20Sopenharmony_ci			pr_err("No UCTL \"refclk-frequency\"\n");
3058c2ecf20Sopenharmony_ci			return -EINVAL;
3068c2ecf20Sopenharmony_ci		}
3078c2ecf20Sopenharmony_ci		i = of_property_read_string(dev->of_node,
3088c2ecf20Sopenharmony_ci					    "refclk-type-ss", &ss_clock_type);
3098c2ecf20Sopenharmony_ci		if (i) {
3108c2ecf20Sopenharmony_ci			pr_err("No UCTL \"refclk-type-ss\"\n");
3118c2ecf20Sopenharmony_ci			return -EINVAL;
3128c2ecf20Sopenharmony_ci		}
3138c2ecf20Sopenharmony_ci		i = of_property_read_string(dev->of_node,
3148c2ecf20Sopenharmony_ci					    "refclk-type-hs", &hs_clock_type);
3158c2ecf20Sopenharmony_ci		if (i) {
3168c2ecf20Sopenharmony_ci			pr_err("No UCTL \"refclk-type-hs\"\n");
3178c2ecf20Sopenharmony_ci			return -EINVAL;
3188c2ecf20Sopenharmony_ci		}
3198c2ecf20Sopenharmony_ci		if (strcmp("dlmc_ref_clk0", ss_clock_type) == 0) {
3208c2ecf20Sopenharmony_ci			if (strcmp(hs_clock_type, "dlmc_ref_clk0") == 0)
3218c2ecf20Sopenharmony_ci				ref_clk_sel = 0;
3228c2ecf20Sopenharmony_ci			else if (strcmp(hs_clock_type, "pll_ref_clk") == 0)
3238c2ecf20Sopenharmony_ci				ref_clk_sel = 2;
3248c2ecf20Sopenharmony_ci			else
3258c2ecf20Sopenharmony_ci				pr_err("Invalid HS clock type %s, using  pll_ref_clk instead\n",
3268c2ecf20Sopenharmony_ci				       hs_clock_type);
3278c2ecf20Sopenharmony_ci		} else if (strcmp(ss_clock_type, "dlmc_ref_clk1") == 0) {
3288c2ecf20Sopenharmony_ci			if (strcmp(hs_clock_type, "dlmc_ref_clk1") == 0)
3298c2ecf20Sopenharmony_ci				ref_clk_sel = 1;
3308c2ecf20Sopenharmony_ci			else if (strcmp(hs_clock_type, "pll_ref_clk") == 0)
3318c2ecf20Sopenharmony_ci				ref_clk_sel = 3;
3328c2ecf20Sopenharmony_ci			else {
3338c2ecf20Sopenharmony_ci				pr_err("Invalid HS clock type %s, using  pll_ref_clk instead\n",
3348c2ecf20Sopenharmony_ci				       hs_clock_type);
3358c2ecf20Sopenharmony_ci				ref_clk_sel = 3;
3368c2ecf20Sopenharmony_ci			}
3378c2ecf20Sopenharmony_ci		} else
3388c2ecf20Sopenharmony_ci			pr_err("Invalid SS clock type %s, using  dlmc_ref_clk0 instead\n",
3398c2ecf20Sopenharmony_ci			       ss_clock_type);
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci		if ((ref_clk_sel == 0 || ref_clk_sel == 1) &&
3428c2ecf20Sopenharmony_ci				  (clock_rate != 100000000))
3438c2ecf20Sopenharmony_ci			pr_err("Invalid UCTL clock rate of %u, using 100000000 instead\n",
3448c2ecf20Sopenharmony_ci			       clock_rate);
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	} else {
3478c2ecf20Sopenharmony_ci		pr_err("No USB UCTL device node\n");
3488c2ecf20Sopenharmony_ci		return -EINVAL;
3498c2ecf20Sopenharmony_ci	}
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	/*
3528c2ecf20Sopenharmony_ci	 * Step 1: Wait for all voltages to be stable...that surely
3538c2ecf20Sopenharmony_ci	 *         happened before starting the kernel. SKIP
3548c2ecf20Sopenharmony_ci	 */
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	/* Step 2: Select GPIO for overcurrent indication, if desired. SKIP */
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	/* Step 3: Assert all resets. */
3598c2ecf20Sopenharmony_ci	uctl_ctl.u64 = cvmx_read_csr(uctl_ctl_reg);
3608c2ecf20Sopenharmony_ci	uctl_ctl.s.uphy_rst = 1;
3618c2ecf20Sopenharmony_ci	uctl_ctl.s.uahc_rst = 1;
3628c2ecf20Sopenharmony_ci	uctl_ctl.s.uctl_rst = 1;
3638c2ecf20Sopenharmony_ci	cvmx_write_csr(uctl_ctl_reg, uctl_ctl.u64);
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	/* Step 4a: Reset the clock dividers. */
3668c2ecf20Sopenharmony_ci	uctl_ctl.u64 = cvmx_read_csr(uctl_ctl_reg);
3678c2ecf20Sopenharmony_ci	uctl_ctl.s.h_clkdiv_rst = 1;
3688c2ecf20Sopenharmony_ci	cvmx_write_csr(uctl_ctl_reg, uctl_ctl.u64);
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	/* Step 4b: Select controller clock frequency. */
3718c2ecf20Sopenharmony_ci	for (div = 0; div < OCTEON_H_CLKDIV_SEL; div++) {
3728c2ecf20Sopenharmony_ci		h_clk_rate = octeon_get_io_clock_rate() / clk_div[div];
3738c2ecf20Sopenharmony_ci		if (h_clk_rate <= OCTEON_MAX_H_CLK_RATE &&
3748c2ecf20Sopenharmony_ci				 h_clk_rate >= OCTEON_MIN_H_CLK_RATE)
3758c2ecf20Sopenharmony_ci			break;
3768c2ecf20Sopenharmony_ci	}
3778c2ecf20Sopenharmony_ci	uctl_ctl.u64 = cvmx_read_csr(uctl_ctl_reg);
3788c2ecf20Sopenharmony_ci	uctl_ctl.s.h_clkdiv_sel = div;
3798c2ecf20Sopenharmony_ci	uctl_ctl.s.h_clk_en = 1;
3808c2ecf20Sopenharmony_ci	cvmx_write_csr(uctl_ctl_reg, uctl_ctl.u64);
3818c2ecf20Sopenharmony_ci	uctl_ctl.u64 = cvmx_read_csr(uctl_ctl_reg);
3828c2ecf20Sopenharmony_ci	if ((div != uctl_ctl.s.h_clkdiv_sel) || (!uctl_ctl.s.h_clk_en)) {
3838c2ecf20Sopenharmony_ci		dev_err(dev, "dwc3 controller clock init failure.\n");
3848c2ecf20Sopenharmony_ci			return -EINVAL;
3858c2ecf20Sopenharmony_ci	}
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	/* Step 4c: Deassert the controller clock divider reset. */
3888c2ecf20Sopenharmony_ci	uctl_ctl.u64 = cvmx_read_csr(uctl_ctl_reg);
3898c2ecf20Sopenharmony_ci	uctl_ctl.s.h_clkdiv_rst = 0;
3908c2ecf20Sopenharmony_ci	cvmx_write_csr(uctl_ctl_reg, uctl_ctl.u64);
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	/* Step 5a: Reference clock configuration. */
3938c2ecf20Sopenharmony_ci	uctl_ctl.u64 = cvmx_read_csr(uctl_ctl_reg);
3948c2ecf20Sopenharmony_ci	uctl_ctl.s.ref_clk_sel = ref_clk_sel;
3958c2ecf20Sopenharmony_ci	uctl_ctl.s.ref_clk_fsel = 0x07;
3968c2ecf20Sopenharmony_ci	uctl_ctl.s.ref_clk_div2 = 0;
3978c2ecf20Sopenharmony_ci	switch (clock_rate) {
3988c2ecf20Sopenharmony_ci	default:
3998c2ecf20Sopenharmony_ci		dev_err(dev, "Invalid ref_clk %u, using 100000000 instead\n",
4008c2ecf20Sopenharmony_ci			clock_rate);
4018c2ecf20Sopenharmony_ci		fallthrough;
4028c2ecf20Sopenharmony_ci	case 100000000:
4038c2ecf20Sopenharmony_ci		mpll_mul = 0x19;
4048c2ecf20Sopenharmony_ci		if (ref_clk_sel < 2)
4058c2ecf20Sopenharmony_ci			uctl_ctl.s.ref_clk_fsel = 0x27;
4068c2ecf20Sopenharmony_ci		break;
4078c2ecf20Sopenharmony_ci	case 50000000:
4088c2ecf20Sopenharmony_ci		mpll_mul = 0x32;
4098c2ecf20Sopenharmony_ci		break;
4108c2ecf20Sopenharmony_ci	case 125000000:
4118c2ecf20Sopenharmony_ci		mpll_mul = 0x28;
4128c2ecf20Sopenharmony_ci		break;
4138c2ecf20Sopenharmony_ci	}
4148c2ecf20Sopenharmony_ci	uctl_ctl.s.mpll_multiplier = mpll_mul;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	/* Step 5b: Configure and enable spread-spectrum for SuperSpeed. */
4178c2ecf20Sopenharmony_ci	uctl_ctl.s.ssc_en = 1;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	/* Step 5c: Enable SuperSpeed. */
4208c2ecf20Sopenharmony_ci	uctl_ctl.s.ref_ssp_en = 1;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	/* Step 5d: Cofngiure PHYs. SKIP */
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	/* Step 6a & 6b: Power up PHYs. */
4258c2ecf20Sopenharmony_ci	uctl_ctl.s.hs_power_en = 1;
4268c2ecf20Sopenharmony_ci	uctl_ctl.s.ss_power_en = 1;
4278c2ecf20Sopenharmony_ci	cvmx_write_csr(uctl_ctl_reg, uctl_ctl.u64);
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	/* Step 7: Wait 10 controller-clock cycles to take effect. */
4308c2ecf20Sopenharmony_ci	udelay(10);
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	/* Step 8a: Deassert UCTL reset signal. */
4338c2ecf20Sopenharmony_ci	uctl_ctl.u64 = cvmx_read_csr(uctl_ctl_reg);
4348c2ecf20Sopenharmony_ci	uctl_ctl.s.uctl_rst = 0;
4358c2ecf20Sopenharmony_ci	cvmx_write_csr(uctl_ctl_reg, uctl_ctl.u64);
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	/* Step 8b: Wait 10 controller-clock cycles. */
4388c2ecf20Sopenharmony_ci	udelay(10);
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	/* Steo 8c: Setup power-power control. */
4418c2ecf20Sopenharmony_ci	if (dwc3_octeon_config_power(dev, base)) {
4428c2ecf20Sopenharmony_ci		dev_err(dev, "Error configuring power.\n");
4438c2ecf20Sopenharmony_ci		return -EINVAL;
4448c2ecf20Sopenharmony_ci	}
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	/* Step 8d: Deassert UAHC reset signal. */
4478c2ecf20Sopenharmony_ci	uctl_ctl.u64 = cvmx_read_csr(uctl_ctl_reg);
4488c2ecf20Sopenharmony_ci	uctl_ctl.s.uahc_rst = 0;
4498c2ecf20Sopenharmony_ci	cvmx_write_csr(uctl_ctl_reg, uctl_ctl.u64);
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	/* Step 8e: Wait 10 controller-clock cycles. */
4528c2ecf20Sopenharmony_ci	udelay(10);
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	/* Step 9: Enable conditional coprocessor clock of UCTL. */
4558c2ecf20Sopenharmony_ci	uctl_ctl.u64 = cvmx_read_csr(uctl_ctl_reg);
4568c2ecf20Sopenharmony_ci	uctl_ctl.s.csclk_en = 1;
4578c2ecf20Sopenharmony_ci	cvmx_write_csr(uctl_ctl_reg, uctl_ctl.u64);
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	/*Step 10: Set for host mode only. */
4608c2ecf20Sopenharmony_ci	uctl_ctl.u64 = cvmx_read_csr(uctl_ctl_reg);
4618c2ecf20Sopenharmony_ci	uctl_ctl.s.drd_mode = 0;
4628c2ecf20Sopenharmony_ci	cvmx_write_csr(uctl_ctl_reg, uctl_ctl.u64);
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	return 0;
4658c2ecf20Sopenharmony_ci}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_cistatic void __init dwc3_octeon_set_endian_mode(u64 base)
4688c2ecf20Sopenharmony_ci{
4698c2ecf20Sopenharmony_ci#define UCTL_SHIM_CFG	0xe8
4708c2ecf20Sopenharmony_ci	union cvm_usbdrd_uctl_shim_cfg shim_cfg;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	shim_cfg.u64 = cvmx_read_csr(base + UCTL_SHIM_CFG);
4738c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN
4748c2ecf20Sopenharmony_ci	shim_cfg.s.dma_endian_mode = 1;
4758c2ecf20Sopenharmony_ci	shim_cfg.s.csr_endian_mode = 1;
4768c2ecf20Sopenharmony_ci#else
4778c2ecf20Sopenharmony_ci	shim_cfg.s.dma_endian_mode = 0;
4788c2ecf20Sopenharmony_ci	shim_cfg.s.csr_endian_mode = 0;
4798c2ecf20Sopenharmony_ci#endif
4808c2ecf20Sopenharmony_ci	cvmx_write_csr(base + UCTL_SHIM_CFG, shim_cfg.u64);
4818c2ecf20Sopenharmony_ci}
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci#define CVMX_USBDRDX_UCTL_CTL(index)				\
4848c2ecf20Sopenharmony_ci		(CVMX_ADD_IO_SEG(0x0001180068000000ull) +	\
4858c2ecf20Sopenharmony_ci		((index & 1) * 0x1000000ull))
4868c2ecf20Sopenharmony_cistatic void __init dwc3_octeon_phy_reset(u64 base)
4878c2ecf20Sopenharmony_ci{
4888c2ecf20Sopenharmony_ci	union cvm_usbdrd_uctl_ctl uctl_ctl;
4898c2ecf20Sopenharmony_ci	int index = (base >> 24) & 1;
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	uctl_ctl.u64 = cvmx_read_csr(CVMX_USBDRDX_UCTL_CTL(index));
4928c2ecf20Sopenharmony_ci	uctl_ctl.s.uphy_rst = 0;
4938c2ecf20Sopenharmony_ci	cvmx_write_csr(CVMX_USBDRDX_UCTL_CTL(index), uctl_ctl.u64);
4948c2ecf20Sopenharmony_ci}
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_cistatic int __init dwc3_octeon_device_init(void)
4978c2ecf20Sopenharmony_ci{
4988c2ecf20Sopenharmony_ci	const char compat_node_name[] = "cavium,octeon-7130-usb-uctl";
4998c2ecf20Sopenharmony_ci	struct platform_device *pdev;
5008c2ecf20Sopenharmony_ci	struct device_node *node;
5018c2ecf20Sopenharmony_ci	struct resource *res;
5028c2ecf20Sopenharmony_ci	void __iomem *base;
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	/*
5058c2ecf20Sopenharmony_ci	 * There should only be three universal controllers, "uctl"
5068c2ecf20Sopenharmony_ci	 * in the device tree. Two USB and a SATA, which we ignore.
5078c2ecf20Sopenharmony_ci	 */
5088c2ecf20Sopenharmony_ci	node = NULL;
5098c2ecf20Sopenharmony_ci	do {
5108c2ecf20Sopenharmony_ci		node = of_find_node_by_name(node, "uctl");
5118c2ecf20Sopenharmony_ci		if (!node)
5128c2ecf20Sopenharmony_ci			return -ENODEV;
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci		if (of_device_is_compatible(node, compat_node_name)) {
5158c2ecf20Sopenharmony_ci			pdev = of_find_device_by_node(node);
5168c2ecf20Sopenharmony_ci			if (!pdev)
5178c2ecf20Sopenharmony_ci				return -ENODEV;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci			res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
5208c2ecf20Sopenharmony_ci			if (res == NULL) {
5218c2ecf20Sopenharmony_ci				put_device(&pdev->dev);
5228c2ecf20Sopenharmony_ci				dev_err(&pdev->dev, "No memory resources\n");
5238c2ecf20Sopenharmony_ci				return -ENXIO;
5248c2ecf20Sopenharmony_ci			}
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci			/*
5278c2ecf20Sopenharmony_ci			 * The code below maps in the registers necessary for
5288c2ecf20Sopenharmony_ci			 * setting up the clocks and reseting PHYs. We must
5298c2ecf20Sopenharmony_ci			 * release the resources so the dwc3 subsystem doesn't
5308c2ecf20Sopenharmony_ci			 * know the difference.
5318c2ecf20Sopenharmony_ci			 */
5328c2ecf20Sopenharmony_ci			base = devm_ioremap_resource(&pdev->dev, res);
5338c2ecf20Sopenharmony_ci			if (IS_ERR(base)) {
5348c2ecf20Sopenharmony_ci				put_device(&pdev->dev);
5358c2ecf20Sopenharmony_ci				return PTR_ERR(base);
5368c2ecf20Sopenharmony_ci			}
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci			mutex_lock(&dwc3_octeon_clocks_mutex);
5398c2ecf20Sopenharmony_ci			dwc3_octeon_clocks_start(&pdev->dev, (u64)base);
5408c2ecf20Sopenharmony_ci			dwc3_octeon_set_endian_mode((u64)base);
5418c2ecf20Sopenharmony_ci			dwc3_octeon_phy_reset((u64)base);
5428c2ecf20Sopenharmony_ci			dev_info(&pdev->dev, "clocks initialized.\n");
5438c2ecf20Sopenharmony_ci			mutex_unlock(&dwc3_octeon_clocks_mutex);
5448c2ecf20Sopenharmony_ci			devm_iounmap(&pdev->dev, base);
5458c2ecf20Sopenharmony_ci			devm_release_mem_region(&pdev->dev, res->start,
5468c2ecf20Sopenharmony_ci						resource_size(res));
5478c2ecf20Sopenharmony_ci			put_device(&pdev->dev);
5488c2ecf20Sopenharmony_ci		}
5498c2ecf20Sopenharmony_ci	} while (node != NULL);
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	return 0;
5528c2ecf20Sopenharmony_ci}
5538c2ecf20Sopenharmony_cidevice_initcall(dwc3_octeon_device_init);
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ciMODULE_AUTHOR("David Daney <david.daney@cavium.com>");
5568c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
5578c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("USB driver for OCTEON III SoC");
558