Commit ce942c0f authored by Ladislav Michl's avatar Ladislav Michl Committed by Thomas Bogendoerfer
Browse files

MIPS: OCTEON: octeon-usb: use bitfields for control register



Code needs to compile for all platforms in order to move it to
drivers/usb/dwc3. Use Linux standard bitfield access macros
to manipulate control register.

Signed-off-by: default avatarLadislav Michl <ladis@linux-mips.org>
Signed-off-by: default avatarThomas Bogendoerfer <tsbogend@alpha.franken.de>
parent c7b6a1eb
Loading
Loading
Loading
Loading
+159 −171
Original line number Diff line number Diff line
@@ -8,36 +8,27 @@
 * for more details.
 */

#include <linux/module.h>
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/device.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/of_platform.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of_platform.h>

#include <asm/octeon/octeon.h>

/*
 * USB Control Register
 */
#define USBDRD_UCTL_CTL				0x00
#define USBDRD_UCTL_BIST_STATUS			0x08
#define USBDRD_UCTL_SPARE0			0x10
#define USBDRD_UCTL_INTSTAT			0x30
#define USBDRD_UCTL_PORT_CFG_HS(port)		(0x40 + (0x20 * port))
#define USBDRD_UCTL_PORT_CFG_SS(port)		(0x48 + (0x20 * port))
#define USBDRD_UCTL_PORT_CR_DBG_CFG(port)	(0x50 + (0x20 * port))
#define USBDRD_UCTL_PORT_CR_DBG_STATUS(port)	(0x58 + (0x20 * port))
#define USBDRD_UCTL_HOST_CFG			0xe0
#define USBDRD_UCTL_SHIM_CFG			0xe8
#define USBDRD_UCTL_ECC				0xf0
#define USBDRD_UCTL_SPARE1			0xf8

/* USB Control Register */
union cvm_usbdrd_uctl_ctl {
	uint64_t u64;
	struct cvm_usbdrd_uctl_ctl_s {
	/* 1 = BIST and set all USB RAMs to 0x0, 0 = BIST */
	__BITFIELD_FIELD(uint64_t clear_bist:1,
/* BIST fast-clear mode select. A BIST run with this bit set
 * clears all entries in USBH RAMs to 0x0.
 */
# define USBDRD_UCTL_CTL_CLEAR_BIST		BIT(63)
/* 1 = Start BIST and cleared by hardware */
	__BITFIELD_FIELD(uint64_t start_bist:1,
# define USBDRD_UCTL_CTL_START_BIST		BIT(62)
/* Reference clock select for SuperSpeed and HighSpeed PLLs:
 *	0x0 = Both PLLs use DLMC_REF_CLK0 for reference clock
 *	0x1 = Both PLLs use DLMC_REF_CLK1 for reference clock
@@ -46,32 +37,32 @@ union cvm_usbdrd_uctl_ctl {
 *	0x3 = SuperSpeed PLL uses DLMC_REF_CLK1 for reference clock &
 *	      HighSpeed PLL uses PLL_REF_CLK for reference clck
 */
	__BITFIELD_FIELD(uint64_t ref_clk_sel:2,
# define USBDRD_UCTL_CTL_REF_CLK_SEL		GENMASK(61, 60)
/* 1 = Spread-spectrum clock enable, 0 = SS clock disable */
	__BITFIELD_FIELD(uint64_t ssc_en:1,
# define USBDRD_UCTL_CTL_SSC_EN			BIT(59)
/* Spread-spectrum clock modulation range:
 *	0x0 = -4980 ppm downspread
 *	0x1 = -4492 ppm downspread
 *	0x2 = -4003 ppm downspread
 *	0x3 - 0x7 = Reserved
 */
	__BITFIELD_FIELD(uint64_t ssc_range:3,
# define USBDRD_UCTL_CTL_SSC_RANGE		GENMASK(58, 56)
/* Enable non-standard oscillator frequencies:
 *	[55:53] = modules -1
 *	[52:47] = 2's complement push amount, 0 = Feature disabled
 */
	__BITFIELD_FIELD(uint64_t ssc_ref_clk_sel:9,
# define USBDRD_UCTL_CTL_SSC_REF_CLK_SEL	GENMASK(55, 47)
/* Reference clock multiplier for non-standard frequencies:
 *	0x19 = 100MHz on DLMC_REF_CLK* if REF_CLK_SEL = 0x0 or 0x1
 *	0x28 = 125MHz on DLMC_REF_CLK* if REF_CLK_SEL = 0x0 or 0x1
 *	0x32 =  50MHz on DLMC_REF_CLK* if REF_CLK_SEL = 0x0 or 0x1
 *	Other Values = Reserved
 */
	__BITFIELD_FIELD(uint64_t mpll_multiplier:7,
# define USBDRD_UCTL_CTL_MPLL_MULTIPLIER	GENMASK(46, 40)
/* Enable reference clock to prescaler for SuperSpeed functionality.
 * Should always be set to "1"
 */
	__BITFIELD_FIELD(uint64_t ref_ssp_en:1,
# define USBDRD_UCTL_CTL_REF_SSP_EN		BIT(39)
/* Divide the reference clock by 2 before entering the
 * REF_CLK_FSEL divider:
 *	If REF_CLK_SEL = 0x0 or 0x1, then only 0x0 is legal
@@ -79,25 +70,21 @@ union cvm_usbdrd_uctl_ctl {
 *		0x1 = DLMC_REF_CLK* is 125MHz
 *		0x0 = DLMC_REF_CLK* is another supported frequency
 */
	__BITFIELD_FIELD(uint64_t ref_clk_div2:1,
# define USBDRD_UCTL_CTL_REF_CLK_DIV2		BIT(38)
/* Select reference clock freqnuency for both PLL blocks:
 *	0x27 = REF_CLK_SEL is 0x0 or 0x1
 *	0x07 = REF_CLK_SEL is 0x2 or 0x3
 */
	__BITFIELD_FIELD(uint64_t ref_clk_fsel:6,
	/* Reserved */
	__BITFIELD_FIELD(uint64_t reserved_31_31:1,
# define USBDRD_UCTL_CTL_REF_CLK_FSEL		GENMASK(37, 32)
/* Controller clock enable. */
	__BITFIELD_FIELD(uint64_t h_clk_en:1,
# define USBDRD_UCTL_CTL_H_CLK_EN		BIT(30)
/* Select bypass input to controller clock divider:
 *	0x0 = Use divided coprocessor clock from H_CLKDIV
 *	0x1 = Use clock from GPIO pins
 */
	__BITFIELD_FIELD(uint64_t h_clk_byp_sel:1,
# define USBDRD_UCTL_CTL_H_CLK_BYP_SEL		BIT(29)
/* Reset controller clock divider. */
	__BITFIELD_FIELD(uint64_t h_clkdiv_rst:1,
	/* Reserved */
	__BITFIELD_FIELD(uint64_t reserved_27_27:1,
# define USBDRD_UCTL_CTL_H_CLKDIV_RST		BIT(28)
/* Clock divider select:
 *	0x0 = divide by 1
 *	0x1 = divide by 2
@@ -108,44 +95,41 @@ union cvm_usbdrd_uctl_ctl {
 *	0x6 = divide by 24
 *	0x7 = divide by 32
 */
	__BITFIELD_FIELD(uint64_t h_clkdiv_sel:3,
	/* Reserved */
	__BITFIELD_FIELD(uint64_t reserved_22_23:2,
# define USBDRD_UCTL_CTL_H_CLKDIV_SEL		GENMASK(26, 24)
/* USB3 port permanently attached: 0x0 = No, 0x1 = Yes */
	__BITFIELD_FIELD(uint64_t usb3_port_perm_attach:1,
# define USBDRD_UCTL_CTL_USB3_PORT_PERM_ATTACH	BIT(21)
/* USB2 port permanently attached: 0x0 = No, 0x1 = Yes */
	__BITFIELD_FIELD(uint64_t usb2_port_perm_attach:1,
	/* Reserved */
	__BITFIELD_FIELD(uint64_t reserved_19_19:1,
# define USBDRD_UCTL_CTL_USB2_PORT_PERM_ATTACH	BIT(20)
/* Disable SuperSpeed PHY: 0x0 = No, 0x1 = Yes */
	__BITFIELD_FIELD(uint64_t usb3_port_disable:1,
	/* Reserved */
	__BITFIELD_FIELD(uint64_t reserved_17_17:1,
# define USBDRD_UCTL_CTL_USB3_PORT_DISABLE	BIT(18)
/* Disable HighSpeed PHY: 0x0 = No, 0x1 = Yes */
	__BITFIELD_FIELD(uint64_t usb2_port_disable:1,
	/* Reserved */
	__BITFIELD_FIELD(uint64_t reserved_15_15:1,
# define USBDRD_UCTL_CTL_USB2_PORT_DISABLE	BIT(16)
/* Enable PHY SuperSpeed block power: 0x0 = No, 0x1 = Yes */
	__BITFIELD_FIELD(uint64_t ss_power_en:1,
	/* Reserved */
	__BITFIELD_FIELD(uint64_t reserved_13_13:1,
# define USBDRD_UCTL_CTL_SS_POWER_EN		BIT(14)
/* Enable PHY HighSpeed block power: 0x0 = No, 0x1 = Yes */
	__BITFIELD_FIELD(uint64_t hs_power_en:1,
	/* Reserved */
	__BITFIELD_FIELD(uint64_t reserved_5_11:7,
# define USBDRD_UCTL_CTL_HS_POWER_EN		BIT(12)
/* Enable USB UCTL interface clock: 0xx = No, 0x1 = Yes */
	__BITFIELD_FIELD(uint64_t csclk_en:1,
# define USBDRD_UCTL_CTL_CSCLK_EN		BIT(4)
/* Controller mode: 0x0 = Host, 0x1 = Device */
	__BITFIELD_FIELD(uint64_t drd_mode:1,
# define USBDRD_UCTL_CTL_DRD_MODE		BIT(3)
/* PHY reset */
	__BITFIELD_FIELD(uint64_t uphy_rst:1,
# define USBDRD_UCTL_CTL_UPHY_RST		BIT(2)
/* Software reset UAHC */
	__BITFIELD_FIELD(uint64_t uahc_rst:1,
# define USBDRD_UCTL_CTL_UAHC_RST		BIT(1)
/* Software resets UCTL */
	__BITFIELD_FIELD(uint64_t uctl_rst:1,
	;)))))))))))))))))))))))))))))))))
	} s;
};
# define USBDRD_UCTL_CTL_UCTL_RST		BIT(0)

#define USBDRD_UCTL_BIST_STATUS			0x08
#define USBDRD_UCTL_SPARE0			0x10
#define USBDRD_UCTL_INTSTAT			0x30
#define USBDRD_UCTL_PORT_CFG_HS(port)		(0x40 + (0x20 * port))
#define USBDRD_UCTL_PORT_CFG_SS(port)		(0x48 + (0x20 * port))
#define USBDRD_UCTL_PORT_CR_DBG_CFG(port)	(0x50 + (0x20 * port))
#define USBDRD_UCTL_PORT_CR_DBG_STATUS(port)	(0x58 + (0x20 * port))
#define USBDRD_UCTL_HOST_CFG			0xe0
#define USBDRD_UCTL_SHIM_CFG			0xe8
#define USBDRD_UCTL_ECC				0xf0
#define USBDRD_UCTL_SPARE1			0xf8

/* UAHC Configuration Register */
union cvm_usbdrd_uctl_host_cfg {
@@ -297,14 +281,10 @@ static int dwc3_octeon_config_power(struct device *dev, u64 base)

static int dwc3_octeon_clocks_start(struct device *dev, u64 base)
{
	union cvm_usbdrd_uctl_ctl uctl_ctl;
	int ref_clk_sel = 2;
	u64 div;
	int i, mpll_mul, ref_clk_fsel, ref_clk_sel = 2;
	u32 clock_rate;
	int mpll_mul;
	int i;
	u64 h_clk_rate;
	u64 uctl_ctl_reg = base;
	u64 div, h_clk_rate, val;
	u64 uctl_ctl_reg = base + USBDRD_UCTL_CTL;

	if (dev->of_node) {
		const char *ss_clock_type;
@@ -368,16 +348,16 @@ static int dwc3_octeon_clocks_start(struct device *dev, u64 base)
	/* Step 2: Select GPIO for overcurrent indication, if desired. SKIP */

	/* Step 3: Assert all resets. */
	uctl_ctl.u64 = cvmx_read_csr(uctl_ctl_reg);
	uctl_ctl.s.uphy_rst = 1;
	uctl_ctl.s.uahc_rst = 1;
	uctl_ctl.s.uctl_rst = 1;
	cvmx_write_csr(uctl_ctl_reg, uctl_ctl.u64);
	val = cvmx_read_csr(uctl_ctl_reg);
	val |= USBDRD_UCTL_CTL_UPHY_RST |
	       USBDRD_UCTL_CTL_UAHC_RST |
	       USBDRD_UCTL_CTL_UCTL_RST;
	cvmx_write_csr(uctl_ctl_reg, val);

	/* Step 4a: Reset the clock dividers. */
	uctl_ctl.u64 = cvmx_read_csr(uctl_ctl_reg);
	uctl_ctl.s.h_clkdiv_rst = 1;
	cvmx_write_csr(uctl_ctl_reg, uctl_ctl.u64);
	val = cvmx_read_csr(uctl_ctl_reg);
	val |= USBDRD_UCTL_CTL_H_CLKDIV_RST;
	cvmx_write_csr(uctl_ctl_reg, val);

	/* Step 4b: Select controller clock frequency. */
	for (div = 0; div < OCTEON_H_CLKDIV_SEL; div++) {
@@ -386,26 +366,29 @@ static int dwc3_octeon_clocks_start(struct device *dev, u64 base)
				 h_clk_rate >= OCTEON_MIN_H_CLK_RATE)
			break;
	}
	uctl_ctl.u64 = cvmx_read_csr(uctl_ctl_reg);
	uctl_ctl.s.h_clkdiv_sel = div;
	uctl_ctl.s.h_clk_en = 1;
	cvmx_write_csr(uctl_ctl_reg, uctl_ctl.u64);
	uctl_ctl.u64 = cvmx_read_csr(uctl_ctl_reg);
	if ((div != uctl_ctl.s.h_clkdiv_sel) || (!uctl_ctl.s.h_clk_en)) {
	val = cvmx_read_csr(uctl_ctl_reg);
	val &= ~USBDRD_UCTL_CTL_H_CLKDIV_SEL;
	val |= FIELD_PREP(USBDRD_UCTL_CTL_H_CLKDIV_SEL, div);
	val |= USBDRD_UCTL_CTL_H_CLK_EN;
	cvmx_write_csr(uctl_ctl_reg, val);
	val = cvmx_read_csr(uctl_ctl_reg);
	if ((div != FIELD_GET(USBDRD_UCTL_CTL_H_CLKDIV_SEL, val)) ||
	    (!(FIELD_GET(USBDRD_UCTL_CTL_H_CLK_EN, val)))) {
		dev_err(dev, "dwc3 controller clock init failure.\n");
			return -EINVAL;
	}

	/* Step 4c: Deassert the controller clock divider reset. */
	uctl_ctl.u64 = cvmx_read_csr(uctl_ctl_reg);
	uctl_ctl.s.h_clkdiv_rst = 0;
	cvmx_write_csr(uctl_ctl_reg, uctl_ctl.u64);
	val &= ~USBDRD_UCTL_CTL_H_CLKDIV_RST;
	cvmx_write_csr(uctl_ctl_reg, val);

	/* Step 5a: Reference clock configuration. */
	uctl_ctl.u64 = cvmx_read_csr(uctl_ctl_reg);
	uctl_ctl.s.ref_clk_sel = ref_clk_sel;
	uctl_ctl.s.ref_clk_fsel = 0x07;
	uctl_ctl.s.ref_clk_div2 = 0;
	val = cvmx_read_csr(uctl_ctl_reg);
	val &= ~USBDRD_UCTL_CTL_REF_CLK_DIV2;
	val &= ~USBDRD_UCTL_CTL_REF_CLK_SEL;
	val |= FIELD_PREP(USBDRD_UCTL_CTL_REF_CLK_SEL, ref_clk_sel);

	ref_clk_fsel = 0x07;
	switch (clock_rate) {
	default:
		dev_warn(dev, "Invalid ref_clk %u, using 100000000 instead\n",
@@ -414,7 +397,7 @@ static int dwc3_octeon_clocks_start(struct device *dev, u64 base)
	case 100000000:
		mpll_mul = 0x19;
		if (ref_clk_sel < 2)
			uctl_ctl.s.ref_clk_fsel = 0x27;
			ref_clk_fsel = 0x27;
		break;
	case 50000000:
		mpll_mul = 0x32;
@@ -423,28 +406,32 @@ static int dwc3_octeon_clocks_start(struct device *dev, u64 base)
		mpll_mul = 0x28;
		break;
	}
	uctl_ctl.s.mpll_multiplier = mpll_mul;
	val &= ~USBDRD_UCTL_CTL_REF_CLK_FSEL;
	val |= FIELD_PREP(USBDRD_UCTL_CTL_REF_CLK_FSEL, ref_clk_fsel);

	val &= ~USBDRD_UCTL_CTL_MPLL_MULTIPLIER;
	val |= FIELD_PREP(USBDRD_UCTL_CTL_MPLL_MULTIPLIER, mpll_mul);

	/* Step 5b: Configure and enable spread-spectrum for SuperSpeed. */
	uctl_ctl.s.ssc_en = 1;
	val |= USBDRD_UCTL_CTL_SSC_EN;

	/* Step 5c: Enable SuperSpeed. */
	uctl_ctl.s.ref_ssp_en = 1;
	val |= USBDRD_UCTL_CTL_REF_SSP_EN;

	/* Step 5d: Configure PHYs. SKIP */

	/* Step 6a & 6b: Power up PHYs. */
	uctl_ctl.s.hs_power_en = 1;
	uctl_ctl.s.ss_power_en = 1;
	cvmx_write_csr(uctl_ctl_reg, uctl_ctl.u64);
	val |= USBDRD_UCTL_CTL_HS_POWER_EN;
	val |= USBDRD_UCTL_CTL_SS_POWER_EN;
	cvmx_write_csr(uctl_ctl_reg, val);

	/* Step 7: Wait 10 controller-clock cycles to take effect. */
	udelay(10);

	/* Step 8a: Deassert UCTL reset signal. */
	uctl_ctl.u64 = cvmx_read_csr(uctl_ctl_reg);
	uctl_ctl.s.uctl_rst = 0;
	cvmx_write_csr(uctl_ctl_reg, uctl_ctl.u64);
	val = cvmx_read_csr(uctl_ctl_reg);
	val &= ~USBDRD_UCTL_CTL_UCTL_RST;
	cvmx_write_csr(uctl_ctl_reg, val);

	/* Step 8b: Wait 10 controller-clock cycles. */
	udelay(10);
@@ -454,22 +441,22 @@ static int dwc3_octeon_clocks_start(struct device *dev, u64 base)
		return -EINVAL;

	/* Step 8d: Deassert UAHC reset signal. */
	uctl_ctl.u64 = cvmx_read_csr(uctl_ctl_reg);
	uctl_ctl.s.uahc_rst = 0;
	cvmx_write_csr(uctl_ctl_reg, uctl_ctl.u64);
	val = cvmx_read_csr(uctl_ctl_reg);
	val &= ~USBDRD_UCTL_CTL_UAHC_RST;
	cvmx_write_csr(uctl_ctl_reg, val);

	/* Step 8e: Wait 10 controller-clock cycles. */
	udelay(10);

	/* Step 9: Enable conditional coprocessor clock of UCTL. */
	uctl_ctl.u64 = cvmx_read_csr(uctl_ctl_reg);
	uctl_ctl.s.csclk_en = 1;
	cvmx_write_csr(uctl_ctl_reg, uctl_ctl.u64);
	val = cvmx_read_csr(uctl_ctl_reg);
	val |= USBDRD_UCTL_CTL_CSCLK_EN;
	cvmx_write_csr(uctl_ctl_reg, val);

	/*Step 10: Set for host mode only. */
	uctl_ctl.u64 = cvmx_read_csr(uctl_ctl_reg);
	uctl_ctl.s.drd_mode = 0;
	cvmx_write_csr(uctl_ctl_reg, uctl_ctl.u64);
	val = cvmx_read_csr(uctl_ctl_reg);
	val &= ~USBDRD_UCTL_CTL_DRD_MODE;
	cvmx_write_csr(uctl_ctl_reg, val);

	return 0;
}
@@ -491,11 +478,12 @@ static void __init dwc3_octeon_set_endian_mode(u64 base)

static void __init dwc3_octeon_phy_reset(u64 base)
{
	union cvm_usbdrd_uctl_ctl uctl_ctl;
	u64 val;
	u64 uctl_ctl_reg = base + USBDRD_UCTL_CTL;

	uctl_ctl.u64 = cvmx_read_csr(base + USBDRD_UCTL_CTL);
	uctl_ctl.s.uphy_rst = 0;
	cvmx_write_csr(base + USBDRD_UCTL_CTL, uctl_ctl.u64);
	val = cvmx_read_csr(uctl_ctl_reg);
	val &= ~USBDRD_UCTL_CTL_UPHY_RST;
	cvmx_write_csr(uctl_ctl_reg, val);
}

static int __init dwc3_octeon_device_init(void)