From 35e3fca7e3ddaa2ae1fe9bd00b22be73e60a6042 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Thu, 25 Aug 2016 12:56:50 +0200 Subject: net: mvneta: Round up top tx buffer boundaries for dcache ops check_cache_range() warns that the top boundaries are not properly aligned when flushing or invalidating the buffers and make these operations fail. This gets rid of the warnings: CACHE: Misaligned operation at range ... Signed-off-by: Stefan Roese Acked-by: Joe Hershberger --- drivers/net/mvneta.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/mvneta.c b/drivers/net/mvneta.c index 6d51b9f..7ed9e29 100644 --- a/drivers/net/mvneta.c +++ b/drivers/net/mvneta.c @@ -1506,7 +1506,8 @@ static int mvneta_send(struct udevice *dev, void *packet, int length) tx_desc->buf_phys_addr = (u32)packet; tx_desc->data_size = length; - flush_dcache_range((u32)packet, (u32)packet + length); + flush_dcache_range((u32)packet, + (u32)packet + ALIGN(length, PKTALIGN)); /* First and Last descriptor */ tx_desc->command = MVNETA_TX_L4_CSUM_NOT | MVNETA_TXD_FLZ_DESC; -- cgit v1.1 From 6985d4966232bfc7bd1a13b46fe3ccbdf46e62f0 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Tue, 17 May 2016 16:36:00 +0200 Subject: serial: Add serial_mvebu_a3700 for Armada 3700 SoC The Armada 3700's UART is a simple serial port. It has a 32 bytes Tx FIFO and a 64 bytes Rx FIFO integrated. This patch adds support for this UART including the DEBUG UART functions for very early debug output. Signed-off-by: Stefan Roese Cc: Nadav Haklai Cc: Kostya Porotchkin Cc: Wilson Ding Cc: Victor Gu Cc: Hua Jing Cc: Terry Zhou Cc: Hanna Hawa Cc: Haim Boot --- drivers/serial/Kconfig | 15 ++++ drivers/serial/Makefile | 1 + drivers/serial/serial_mvebu_a3700.c | 175 ++++++++++++++++++++++++++++++++++++ 3 files changed, 191 insertions(+) create mode 100644 drivers/serial/serial_mvebu_a3700.c (limited to 'drivers') diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index ab5df70..541cf2e 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -147,6 +147,13 @@ config DEBUG_UART_ARM_DCC This port is available at least on ARMv6, ARMv7, ARMv8 and XScale architectures. +config DEBUG_MVEBU_A3700_UART + bool "Marvell Armada 3700" + help + Select this to enable a debug UART using the serial_mvebu driver. You + will need to provide parameters to make this work. The driver will + be available until the real driver-model serial is running. + config DEBUG_UART_ZYNQ bool "Xilinx Zynq" help @@ -295,6 +302,13 @@ config FSL_LPUART Select this to enable a Low Power UART for Freescale VF610 and QorIQ Layerscape devices. +config MVEBU_A3700_UART + bool "UART support for Armada 3700" + default n + help + Choose this option to add support for UART driver on the Marvell + Armada 3700 SoC. The base address is configured via DT. + config PIC32_SERIAL bool "Support for Microchip PIC32 on-chip UART" depends on DM_SERIAL && MACH_PIC32 @@ -371,4 +385,5 @@ config MSM_SERIAL It should support all Qualcomm devices with UARTDM version 1.4, for example APQ8016 and MSM8916. Single baudrate is supported in current implementation (115200). + endmenu diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 6986d65..21b1292 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_PIC32_SERIAL) += serial_pic32.o obj-$(CONFIG_STM32X7_SERIAL) += serial_stm32x7.o obj-$(CONFIG_BCM283X_MU_SERIAL) += serial_bcm283x_mu.o obj-$(CONFIG_MSM_SERIAL) += serial_msm.o +obj-$(CONFIG_MVEBU_A3700_UART) += serial_mvebu_a3700.o ifndef CONFIG_SPL_BUILD obj-$(CONFIG_USB_TTY) += usbtty.o diff --git a/drivers/serial/serial_mvebu_a3700.c b/drivers/serial/serial_mvebu_a3700.c new file mode 100644 index 0000000..192e79a --- /dev/null +++ b/drivers/serial/serial_mvebu_a3700.c @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2016 Stefan Roese + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +struct mvebu_platdata { + void __iomem *base; +}; + +/* + * Register offset + */ +#define UART_RX_REG 0x00 +#define UART_TX_REG 0x04 +#define UART_CTRL_REG 0x08 +#define UART_STATUS_REG 0x0c +#define UART_BAUD_REG 0x10 +#define UART_POSSR_REG 0x14 + +#define UART_STATUS_RX_RDY 0x10 +#define UART_STATUS_TXFIFO_FULL 0x800 + +#define UART_CTRL_RXFIFO_RESET 0x4000 +#define UART_CTRL_TXFIFO_RESET 0x8000 + +#define CONFIG_UART_BASE_CLOCK 25804800 + +static int mvebu_serial_putc(struct udevice *dev, const char ch) +{ + struct mvebu_platdata *plat = dev_get_platdata(dev); + void __iomem *base = plat->base; + + while (readl(base + UART_STATUS_REG) & UART_STATUS_TXFIFO_FULL) + ; + + writel(ch, base + UART_TX_REG); + + return 0; +} + +static int mvebu_serial_getc(struct udevice *dev) +{ + struct mvebu_platdata *plat = dev_get_platdata(dev); + void __iomem *base = plat->base; + + while (!(readl(base + UART_STATUS_REG) & UART_STATUS_RX_RDY)) + ; + + return readl(base + UART_RX_REG) & 0xff; +} + +static int mvebu_serial_pending(struct udevice *dev, bool input) +{ + struct mvebu_platdata *plat = dev_get_platdata(dev); + void __iomem *base = plat->base; + + if (readl(base + UART_STATUS_REG) & UART_STATUS_RX_RDY) + return 1; + + return 0; +} + +static int mvebu_serial_setbrg(struct udevice *dev, int baudrate) +{ + struct mvebu_platdata *plat = dev_get_platdata(dev); + void __iomem *base = plat->base; + + /* + * Calculate divider + * baudrate = clock / 16 / divider + */ + writel(CONFIG_UART_BASE_CLOCK / baudrate / 16, base + UART_BAUD_REG); + + /* + * Set Programmable Oversampling Stack to 0, + * UART defaults to 16x scheme + */ + writel(0, base + UART_POSSR_REG); + + return 0; +} + +static int mvebu_serial_probe(struct udevice *dev) +{ + struct mvebu_platdata *plat = dev_get_platdata(dev); + void __iomem *base = plat->base; + + /* reset FIFOs */ + writel(UART_CTRL_RXFIFO_RESET | UART_CTRL_TXFIFO_RESET, + base + UART_CTRL_REG); + + /* No Parity, 1 Stop */ + writel(0, base + UART_CTRL_REG); + + return 0; +} + +static int mvebu_serial_ofdata_to_platdata(struct udevice *dev) +{ + struct mvebu_platdata *plat = dev_get_platdata(dev); + + plat->base = dev_get_addr_ptr(dev); + + return 0; +} + +static const struct dm_serial_ops mvebu_serial_ops = { + .putc = mvebu_serial_putc, + .pending = mvebu_serial_pending, + .getc = mvebu_serial_getc, + .setbrg = mvebu_serial_setbrg, +}; + +static const struct udevice_id mvebu_serial_ids[] = { + { .compatible = "marvell,armada-3700-uart" }, + { } +}; + +U_BOOT_DRIVER(serial_mvebu) = { + .name = "serial_mvebu", + .id = UCLASS_SERIAL, + .of_match = mvebu_serial_ids, + .ofdata_to_platdata = mvebu_serial_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct mvebu_platdata), + .probe = mvebu_serial_probe, + .ops = &mvebu_serial_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +#ifdef CONFIG_DEBUG_MVEBU_A3700_UART + +#include + +static inline void _debug_uart_init(void) +{ + void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE; + + /* reset FIFOs */ + writel(UART_CTRL_RXFIFO_RESET | UART_CTRL_TXFIFO_RESET, + base + UART_CTRL_REG); + + /* No Parity, 1 Stop */ + writel(0, base + UART_CTRL_REG); + + /* + * Calculate divider + * baudrate = clock / 16 / divider + */ + writel(CONFIG_UART_BASE_CLOCK / 115200 / 16, base + UART_BAUD_REG); + + /* + * Set Programmable Oversampling Stack to 0, + * UART defaults to 16x scheme + */ + writel(0, base + UART_POSSR_REG); +} + +static inline void _debug_uart_putc(int ch) +{ + void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE; + + while (readl(base + UART_STATUS_REG) & UART_STATUS_TXFIFO_FULL) + ; + + writel(ch, base + UART_TX_REG); +} + +DEBUG_UART_FUNCS +#endif -- cgit v1.1 From 3fda4ef39557c070558d51c4ea4562c370c3f96d Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Thu, 19 May 2016 15:56:44 +0200 Subject: spi: Add driver for Marvell Armada 3700 SoC The SPI IP core in the Marvell Armada 3700 is similar to the one in the other Armada SoCs. But the differences are big enough that it makes sense to introduce a new driver instead of cluttering the old kirkwood driver with #ifdef's. Signed-off-by: Stefan Roese Cc: Nadav Haklai Cc: Kostya Porotchkin Cc: Wilson Ding Cc: Victor Gu Cc: Hua Jing Cc: Terry Zhou Cc: Hanna Hawa Cc: Haim Boot Reviewed-by: Jagan Teki --- drivers/spi/Kconfig | 7 + drivers/spi/Makefile | 1 + drivers/spi/mvebu_a3700_spi.c | 295 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 303 insertions(+) create mode 100644 drivers/spi/mvebu_a3700_spi.c (limited to 'drivers') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 5da66a6..8724f87 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -68,6 +68,13 @@ config ICH_SPI access the SPI NOR flash on platforms embedding this Intel ICH IP core. +config MVEBU_A3700_SPI + bool "Marvell Armada 3700 SPI driver" + help + Enable the Marvell Armada 3700 SPI driver. This driver can be + used to access the SPI NOR flash on platforms embedding this + Marvell IP core. + config PIC32_SPI bool "Microchip PIC32 SPI driver" depends on MACH_PIC32 diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index b1d9e20..247c5f6 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o obj-$(CONFIG_LPC32XX_SSP) += lpc32xx_ssp.o obj-$(CONFIG_MPC52XX_SPI) += mpc52xx_spi.o obj-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o +obj-$(CONFIG_MVEBU_A3700_SPI) += mvebu_a3700_spi.o obj-$(CONFIG_MXC_SPI) += mxc_spi.o obj-$(CONFIG_MXS_SPI) += mxs_spi.o obj-$(CONFIG_OMAP3_SPI) += omap3_spi.o diff --git a/drivers/spi/mvebu_a3700_spi.c b/drivers/spi/mvebu_a3700_spi.c new file mode 100644 index 0000000..7c58c36 --- /dev/null +++ b/drivers/spi/mvebu_a3700_spi.c @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2015 Marvell International Ltd. + * + * Copyright (C) 2016 Stefan Roese + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +#define MVEBU_SPI_A3700_XFER_RDY BIT(1) +#define MVEBU_SPI_A3700_FIFO_FLUSH BIT(9) +#define MVEBU_SPI_A3700_BYTE_LEN BIT(5) +#define MVEBU_SPI_A3700_CLK_PHA BIT(6) +#define MVEBU_SPI_A3700_CLK_POL BIT(7) +#define MVEBU_SPI_A3700_FIFO_EN BIT(17) +#define MVEBU_SPI_A3700_SPI_EN_0 BIT(16) +#define MVEBU_SPI_A3700_CLK_PRESCALE_BIT 0 +#define MVEBU_SPI_A3700_CLK_PRESCALE_MASK \ + (0x1f << MVEBU_SPI_A3700_CLK_PRESCALE_BIT) + +/* SPI registers */ +struct spi_reg { + u32 ctrl; /* 0x10600 */ + u32 cfg; /* 0x10604 */ + u32 dout; /* 0x10608 */ + u32 din; /* 0x1060c */ +}; + +struct mvebu_spi_platdata { + struct spi_reg *spireg; + unsigned int frequency; + unsigned int clock; +}; + +static void spi_cs_activate(struct spi_reg *reg, int cs) +{ + setbits_le32(®->ctrl, MVEBU_SPI_A3700_SPI_EN_0 << cs); +} + +static void spi_cs_deactivate(struct spi_reg *reg, int cs) +{ + clrbits_le32(®->ctrl, MVEBU_SPI_A3700_SPI_EN_0 << cs); +} + +/** + * spi_legacy_shift_byte() - triggers the real SPI transfer + * @bytelen: Indicate how many bytes to transfer. + * @dout: Buffer address of what to send. + * @din: Buffer address of where to receive. + * + * This function triggers the real SPI transfer in legacy mode. It + * will shift out char buffer from @dout, and shift in char buffer to + * @din, if necessary. + * + * This function assumes that only one byte is shifted at one time. + * However, it is not its responisbility to set the transfer type to + * one-byte. Also, it does not guarantee that it will work if transfer + * type becomes two-byte. See spi_set_legacy() for details. + * + * In legacy mode, simply write to the SPI_DOUT register will trigger + * the transfer. + * + * If @dout == NULL, which means no actual data needs to be sent out, + * then the function will shift out 0x00 in order to shift in data. + * The XFER_RDY flag is checked every time before accessing SPI_DOUT + * and SPI_DIN register. + * + * The number of transfers to be triggerred is decided by @bytelen. + * + * Return: 0 - cool + * -ETIMEDOUT - XFER_RDY flag timeout + */ +static int spi_legacy_shift_byte(struct spi_reg *reg, unsigned int bytelen, + const void *dout, void *din) +{ + const u8 *dout_8; + u8 *din_8; + int ret; + + /* Use 0x00 as dummy dout */ + const u8 dummy_dout = 0x0; + u32 pending_dout = 0x0; + + /* dout_8: pointer of current dout */ + dout_8 = dout; + /* din_8: pointer of current din */ + din_8 = din; + + while (bytelen) { + ret = wait_for_bit(__func__, ®->ctrl, + MVEBU_SPI_A3700_XFER_RDY, true, 100, false); + if (ret) + return ret; + + if (dout) + pending_dout = (u32)*dout_8; + else + pending_dout = (u32)dummy_dout; + + /* Trigger the xfer */ + writel(pending_dout, ®->dout); + + if (din) { + ret = wait_for_bit(__func__, ®->ctrl, + MVEBU_SPI_A3700_XFER_RDY, + true, 100, false); + if (ret) + return ret; + + /* Read what is transferred in */ + *din_8 = (u8)readl(®->din); + } + + /* Don't increment the current pointer if NULL */ + if (dout) + dout_8++; + if (din) + din_8++; + + bytelen--; + } + + return 0; +} + +static int mvebu_spi_xfer(struct udevice *dev, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct udevice *bus = dev->parent; + struct mvebu_spi_platdata *plat = dev_get_platdata(bus); + struct spi_reg *reg = plat->spireg; + unsigned int bytelen; + int ret; + + bytelen = bitlen / 8; + + if (dout && din) + debug("This is a duplex transfer.\n"); + + /* Activate CS */ + if (flags & SPI_XFER_BEGIN) { + debug("SPI: activate cs.\n"); + spi_cs_activate(reg, spi_chip_select(dev)); + } + + /* Send and/or receive */ + if (dout || din) { + ret = spi_legacy_shift_byte(reg, bytelen, dout, din); + if (ret) + return ret; + } + + /* Deactivate CS */ + if (flags & SPI_XFER_END) { + ret = wait_for_bit(__func__, ®->ctrl, + MVEBU_SPI_A3700_XFER_RDY, true, 100, false); + if (ret) + return ret; + + debug("SPI: deactivate cs.\n"); + spi_cs_deactivate(reg, spi_chip_select(dev)); + } + + return 0; +} + +static int mvebu_spi_set_speed(struct udevice *bus, uint hz) +{ + struct mvebu_spi_platdata *plat = dev_get_platdata(bus); + struct spi_reg *reg = plat->spireg; + u32 data; + + data = readl(®->cfg); + + /* Set Prescaler */ + data &= ~MVEBU_SPI_A3700_CLK_PRESCALE_MASK; + + /* Calculate Prescaler = (spi_input_freq / spi_max_freq) */ + if (hz > plat->frequency) + hz = plat->frequency; + data |= plat->clock / hz; + + writel(data, ®->cfg); + + return 0; +} + +static int mvebu_spi_set_mode(struct udevice *bus, uint mode) +{ + struct mvebu_spi_platdata *plat = dev_get_platdata(bus); + struct spi_reg *reg = plat->spireg; + + /* + * Set SPI polarity + * 0: Serial interface clock is low when inactive + * 1: Serial interface clock is high when inactive + */ + if (mode & SPI_CPOL) + setbits_le32(®->cfg, MVEBU_SPI_A3700_CLK_POL); + else + clrbits_le32(®->cfg, MVEBU_SPI_A3700_CLK_POL); + if (mode & SPI_CPHA) + setbits_le32(®->cfg, MVEBU_SPI_A3700_CLK_PHA); + else + clrbits_le32(®->cfg, MVEBU_SPI_A3700_CLK_PHA); + + return 0; +} + +static int mvebu_spi_probe(struct udevice *bus) +{ + struct mvebu_spi_platdata *plat = dev_get_platdata(bus); + struct spi_reg *reg = plat->spireg; + u32 data; + int ret; + + /* + * Settings SPI controller to be working in legacy mode, which + * means use only DO pin (I/O 1) for Data Out, and DI pin (I/O 0) + * for Data In. + */ + + /* Flush read/write FIFO */ + data = readl(®->cfg); + writel(data | MVEBU_SPI_A3700_FIFO_FLUSH, ®->cfg); + ret = wait_for_bit(__func__, ®->cfg, MVEBU_SPI_A3700_FIFO_FLUSH, + false, 1000, false); + if (ret) + return ret; + + /* Disable FIFO mode */ + data &= ~MVEBU_SPI_A3700_FIFO_EN; + + /* Always shift 1 byte at a time */ + data &= ~MVEBU_SPI_A3700_BYTE_LEN; + + writel(data, ®->cfg); + + return 0; +} + +static int mvebu_spi_ofdata_to_platdata(struct udevice *bus) +{ + struct mvebu_spi_platdata *plat = dev_get_platdata(bus); + + plat->spireg = (struct spi_reg *)dev_get_addr(bus); + + /* + * FIXME + * Right now, mvebu does not have a clock infrastructure in U-Boot + * which should be used to query the input clock to the SPI + * controller. Once this clock driver is integrated into U-Boot + * it should be used to read the input clock and the DT property + * can be removed. + */ + plat->clock = fdtdec_get_int(gd->fdt_blob, bus->of_offset, + "clock-frequency", 160000); + plat->frequency = fdtdec_get_int(gd->fdt_blob, bus->of_offset, + "spi-max-frequency", 40000); + + return 0; +} + +static const struct dm_spi_ops mvebu_spi_ops = { + .xfer = mvebu_spi_xfer, + .set_speed = mvebu_spi_set_speed, + .set_mode = mvebu_spi_set_mode, + /* + * cs_info is not needed, since we require all chip selects to be + * in the device tree explicitly + */ +}; + +static const struct udevice_id mvebu_spi_ids[] = { + { .compatible = "marvell,armada-3700-spi" }, + { } +}; + +U_BOOT_DRIVER(mvebu_spi) = { + .name = "mvebu_spi", + .id = UCLASS_SPI, + .of_match = mvebu_spi_ids, + .ops = &mvebu_spi_ops, + .ofdata_to_platdata = mvebu_spi_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct mvebu_spi_platdata), + .probe = mvebu_spi_probe, +}; -- cgit v1.1 From 3cbc11da866936c04ef95ea077e891d907cd4ad9 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Thu, 19 May 2016 18:09:17 +0200 Subject: net: mvneta: Make driver 64bit safe The mvneta driver is also used on the ARMv8 64bit Armada 3700 SoC. This patch fixes the compilation warnings seen on this 64bit platform. Signed-off-by: Stefan Roese Cc: Nadav Haklai Cc: Kostya Porotchkin Cc: Wilson Ding Cc: Victor Gu Cc: Hua Jing Cc: Terry Zhou Cc: Hanna Hawa Cc: Haim Boot Acked-by: Joe Hershberger --- drivers/net/mvneta.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mvneta.c b/drivers/net/mvneta.c index 7ed9e29..a1bf227 100644 --- a/drivers/net/mvneta.c +++ b/drivers/net/mvneta.c @@ -1022,7 +1022,7 @@ static int mvneta_txq_init(struct mvneta_port *pp, txq->size = pp->tx_ring_size; /* Allocate memory for TX descriptors */ - txq->descs_phys = (u32)txq->descs; + txq->descs_phys = (dma_addr_t)txq->descs; if (txq->descs == NULL) return -ENOMEM; @@ -1504,10 +1504,10 @@ static int mvneta_send(struct udevice *dev, void *packet, int length) /* Get a descriptor for the first part of the packet */ tx_desc = mvneta_txq_next_desc_get(txq); - tx_desc->buf_phys_addr = (u32)packet; + tx_desc->buf_phys_addr = (u32)(uintptr_t)packet; tx_desc->data_size = length; - flush_dcache_range((u32)packet, - (u32)packet + ALIGN(length, PKTALIGN)); + flush_dcache_range((ulong)packet, + (ulong)packet + ALIGN(length, PKTALIGN)); /* First and Last descriptor */ tx_desc->command = MVNETA_TX_L4_CSUM_NOT | MVNETA_TXD_FLZ_DESC; @@ -1563,7 +1563,7 @@ static int mvneta_recv(struct udevice *dev, int flags, uchar **packetp) rx_bytes = rx_desc->data_size - 6; /* give packet to stack - skip on first 2 bytes */ - data = (u8 *)rx_desc->buf_cookie + 2; + data = (u8 *)(uintptr_t)rx_desc->buf_cookie + 2; /* * No cache invalidation needed here, since the rx_buffer's are * located in a uncached memory region @@ -1594,13 +1594,13 @@ static int mvneta_probe(struct udevice *dev) if (!buffer_loc.tx_descs) { /* Align buffer area for descs and rx_buffers to 1MiB */ bd_space = memalign(1 << MMU_SECTION_SHIFT, BD_SPACE); - mmu_set_region_dcache_behaviour((u32)bd_space, BD_SPACE, + mmu_set_region_dcache_behaviour((phys_addr_t)bd_space, BD_SPACE, DCACHE_OFF); buffer_loc.tx_descs = (struct mvneta_tx_desc *)bd_space; buffer_loc.rx_descs = (struct mvneta_rx_desc *) - ((u32)bd_space + + ((phys_addr_t)bd_space + MVNETA_MAX_TXD * sizeof(struct mvneta_tx_desc)); - buffer_loc.rx_buffers = (u32) + buffer_loc.rx_buffers = (phys_addr_t) (bd_space + MVNETA_MAX_TXD * sizeof(struct mvneta_tx_desc) + MVNETA_MAX_RXD * sizeof(struct mvneta_rx_desc)); -- cgit v1.1 From 544eefe084661d5ee486aca0cd0ec03801bfced9 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Thu, 19 May 2016 17:46:36 +0200 Subject: net: mvneta: Add support for Armada 3700 SoC This patch adds support for the Armada 3700 SoC to the Marvell mvneta network driver. Not like A380, in Armada3700, there are two layers of decode windows for GBE: First layer is: GbE Address window that resides inside the GBE unit, Second layer is: Fabric address window which is located in the NIC400 (South Fabric). To simplify the address decode configuration for Armada3700, we bypass the first layer of GBE decode window by setting the first window to 4GB. Signed-off-by: Stefan Roese Cc: Nadav Haklai Cc: Kostya Porotchkin Cc: Wilson Ding Cc: Victor Gu Cc: Hua Jing Cc: Terry Zhou Cc: Hanna Hawa Cc: Haim Boot Acked-by: Joe Hershberger --- drivers/net/mvneta.c | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/mvneta.c b/drivers/net/mvneta.c index a1bf227..51bb569 100644 --- a/drivers/net/mvneta.c +++ b/drivers/net/mvneta.c @@ -91,7 +91,11 @@ DECLARE_GLOBAL_DATA_PTR; #define MVNETA_WIN_BASE(w) (0x2200 + ((w) << 3)) #define MVNETA_WIN_SIZE(w) (0x2204 + ((w) << 3)) #define MVNETA_WIN_REMAP(w) (0x2280 + ((w) << 2)) +#define MVNETA_WIN_SIZE_MASK (0xffff0000) #define MVNETA_BASE_ADDR_ENABLE 0x2290 +#define MVNETA_BASE_ADDR_ENABLE_BIT 0x1 +#define MVNETA_PORT_ACCESS_PROTECT 0x2294 +#define MVNETA_PORT_ACCESS_PROTECT_WIN0_RW 0x3 #define MVNETA_PORT_CONFIG 0x2400 #define MVNETA_UNI_PROMISC_MODE BIT(0) #define MVNETA_DEF_RXQ(q) ((q) << 1) @@ -1241,6 +1245,32 @@ static int mvneta_init2(struct mvneta_port *pp) } /* platform glue : initialize decoding windows */ + +/* + * Not like A380, in Armada3700, there are two layers of decode windows for GBE: + * First layer is: GbE Address window that resides inside the GBE unit, + * Second layer is: Fabric address window which is located in the NIC400 + * (South Fabric). + * To simplify the address decode configuration for Armada3700, we bypass the + * first layer of GBE decode window by setting the first window to 4GB. + */ +static void mvneta_bypass_mbus_windows(struct mvneta_port *pp) +{ + /* + * Set window size to 4GB, to bypass GBE address decode, leave the + * work to MBUS decode window + */ + mvreg_write(pp, MVNETA_WIN_SIZE(0), MVNETA_WIN_SIZE_MASK); + + /* Enable GBE address decode window 0 by set bit 0 to 0 */ + clrbits_le32(pp->base + MVNETA_BASE_ADDR_ENABLE, + MVNETA_BASE_ADDR_ENABLE_BIT); + + /* Set GBE address decode window 0 to full Access (read or write) */ + setbits_le32(pp->base + MVNETA_PORT_ACCESS_PROTECT, + MVNETA_PORT_ACCESS_PROTECT_WIN0_RW); +} + static void mvneta_conf_mbus_windows(struct mvneta_port *pp) { const struct mbus_dram_target_info *dram; @@ -1609,7 +1639,10 @@ static int mvneta_probe(struct udevice *dev) pp->base = (void __iomem *)pdata->iobase; /* Configure MBUS address windows */ - mvneta_conf_mbus_windows(pp); + if (of_device_is_compatible(dev, "marvell,armada-3700-neta")) + mvneta_bypass_mbus_windows(pp); + else + mvneta_conf_mbus_windows(pp); /* PHY interface is already decoded in mvneta_ofdata_to_platdata() */ pp->phy_interface = pdata->phy_interface; @@ -1672,6 +1705,7 @@ static int mvneta_ofdata_to_platdata(struct udevice *dev) static const struct udevice_id mvneta_ids[] = { { .compatible = "marvell,armada-370-neta" }, { .compatible = "marvell,armada-xp-neta" }, + { .compatible = "marvell,armada-3700-neta" }, { } }; -- cgit v1.1 From 81c1f6f0c3b05ae07c521c2dce579f0cb0816926 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Thu, 14 Jul 2016 11:39:20 +0200 Subject: usb: xhci: Add Marvell MVEBU xHCI support This patch adds DM based support for the xHCI USB 3.0 controller integrated in the Armada 3700 SoC. It may be extended to be used by other MVEBU SoCs as well. Signed-off-by: Stefan Roese Cc: Nadav Haklai Cc: Kostya Porotchkin Cc: Wilson Ding Cc: Victor Gu Cc: Hua Jing Cc: Terry Zhou Cc: Hanna Hawa Cc: Haim Boot Acked-by: Marek Vasut --- drivers/usb/host/Kconfig | 9 ++++ drivers/usb/host/Makefile | 1 + drivers/usb/host/xhci-mvebu.c | 96 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+) create mode 100644 drivers/usb/host/xhci-mvebu.c (limited to 'drivers') diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 61e13d7..b9c5fbe 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -21,6 +21,15 @@ config USB_XHCI_DWC3 Say Y or if your system has a Dual Role SuperSpeed USB controller based on the DesignWare USB3 IP Core. +config USB_XHCI_MVEBU + bool "MVEBU USB 3.0 support" + default y + depends on ARCH_MVEBU + help + Choose this option to add support for USB 3.0 driver on mvebu + SoCs, which includes Armada8K, Armada3700 and other Armada + family SoCs. + config USB_XHCI_ROCKCHIP bool "Support for Rockchip on-chip xHCI USB controller" depends on ARCH_ROCKCHIP diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index de25328..58c0cf5 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -61,6 +61,7 @@ obj-$(CONFIG_USB_XHCI_ZYNQMP) += xhci-zynqmp.o obj-$(CONFIG_USB_XHCI_KEYSTONE) += xhci-keystone.o obj-$(CONFIG_USB_XHCI_EXYNOS) += xhci-exynos5.o obj-$(CONFIG_USB_XHCI_FSL) += xhci-fsl.o +obj-$(CONFIG_USB_XHCI_MVEBU) += xhci-mvebu.o obj-$(CONFIG_USB_XHCI_OMAP) += xhci-omap.o obj-$(CONFIG_USB_XHCI_PCI) += xhci-pci.o diff --git a/drivers/usb/host/xhci-mvebu.c b/drivers/usb/host/xhci-mvebu.c new file mode 100644 index 0000000..e09e87a --- /dev/null +++ b/drivers/usb/host/xhci-mvebu.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2015 Marvell International Ltd. + * + * MVEBU USB HOST xHCI Controller + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +#include "xhci.h" + +DECLARE_GLOBAL_DATA_PTR; + +struct mvebu_xhci_platdata { + fdt_addr_t hcd_base; +}; + +/** + * Contains pointers to register base addresses + * for the usb controller. + */ +struct mvebu_xhci { + struct xhci_ctrl ctrl; /* Needs to come first in this struct! */ + struct usb_platdata usb_plat; + struct xhci_hccr *hcd; +}; + +/* + * Dummy implementation that can be overwritten by a board + * specific function + */ +__weak int board_xhci_enable(void) +{ + return 0; +} + +static int xhci_usb_probe(struct udevice *dev) +{ + struct mvebu_xhci_platdata *plat = dev_get_platdata(dev); + struct mvebu_xhci *ctx = dev_get_priv(dev); + struct xhci_hcor *hcor; + int len; + + ctx->hcd = (struct xhci_hccr *)plat->hcd_base; + len = HC_LENGTH(xhci_readl(&ctx->hcd->cr_capbase)); + hcor = (struct xhci_hcor *)((uintptr_t)ctx->hcd + len); + + /* Enable USB xHCI (VBUS, reset etc) in board specific code */ + board_xhci_enable(); + + return xhci_register(dev, ctx->hcd, hcor); +} + +static int xhci_usb_remove(struct udevice *dev) +{ + return xhci_deregister(dev); +} + +static int xhci_usb_ofdata_to_platdata(struct udevice *dev) +{ + struct mvebu_xhci_platdata *plat = dev_get_platdata(dev); + + /* + * Get the base address for XHCI controller from the device node + */ + plat->hcd_base = dev_get_addr(dev); + if (plat->hcd_base == FDT_ADDR_T_NONE) { + debug("Can't get the XHCI register base address\n"); + return -ENXIO; + } + + return 0; +} + +static const struct udevice_id xhci_usb_ids[] = { + { .compatible = "marvell,armada3700-xhci" }, + { } +}; + +U_BOOT_DRIVER(usb_xhci) = { + .name = "xhci_mvebu", + .id = UCLASS_USB, + .of_match = xhci_usb_ids, + .ofdata_to_platdata = xhci_usb_ofdata_to_platdata, + .probe = xhci_usb_probe, + .remove = xhci_usb_remove, + .ops = &xhci_usb_ops, + .platdata_auto_alloc_size = sizeof(struct mvebu_xhci_platdata), + .priv_auto_alloc_size = sizeof(struct mvebu_xhci), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; -- cgit v1.1 From c6cfcc91ea59d800672274a056eefa93a10711e9 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Mon, 18 Jul 2016 17:24:56 +0200 Subject: usb: ehci: ehci-marvell.c: Add Armada 3700 support (ARMv8) This patch adds DM based support for the Armada 3700 EHCI controller. The address windows don't need to get configured in this case. The difference here is detected via DT compatible property at runtime. With this support and the DM xHCI driver, both XHCI and eHCI can be used simultaniously on the MVEBU boards now. Signed-off-by: Stefan Roese Cc: Nadav Haklai Cc: Kostya Porotchkin Cc: Wilson Ding Cc: Victor Gu Cc: Hua Jing Cc: Terry Zhou Cc: Hanna Hawa Cc: Haim Boot Acked-by: Marek Vasut --- drivers/usb/host/ehci-marvell.c | 59 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ehci-marvell.c b/drivers/usb/host/ehci-marvell.c index 253fcb3..4642470 100644 --- a/drivers/usb/host/ehci-marvell.c +++ b/drivers/usb/host/ehci-marvell.c @@ -26,6 +26,16 @@ DECLARE_GLOBAL_DATA_PTR; #define USB_WINDOW_BASE(i) (0x324 + ((i) << 4)) #define USB_TARGET_DRAM 0x0 +#define USB2_SBUSCFG_OFF 0x90 + +#define USB_SBUSCFG_BAWR_OFF 0x6 +#define USB_SBUSCFG_BARD_OFF 0x3 +#define USB_SBUSCFG_AHBBRST_OFF 0x0 + +#define USB_SBUSCFG_BAWR_ALIGN_64B 0x4 +#define USB_SBUSCFG_BARD_ALIGN_64B 0x4 +#define USB_SBUSCFG_AHBBRST_INCR16 0x7 + /* * USB 2.0 Bridge Address Decoding registers setup */ @@ -41,7 +51,7 @@ struct ehci_mvebu_priv { * to the common mvebu archticture including the mbus setup, this * will be the only function needed to configure the access windows */ -static void usb_brg_adrdec_setup(u32 base) +static void usb_brg_adrdec_setup(void *base) { const struct mbus_dram_target_info *dram; int i; @@ -66,6 +76,29 @@ static void usb_brg_adrdec_setup(u32 base) } } +static void marvell_ehci_powerup_fixup(struct ehci_ctrl *ctrl, + uint32_t *status_reg, uint32_t *reg) +{ + struct ehci_mvebu_priv *priv = ctrl->priv; + + /* + * Set default value for reg SBUSCFG, which is Control for the AMBA + * system bus interface: + * BAWR = BARD = 4 : Align rd/wr bursts packets larger than 64 bytes + * AHBBRST = 7 : Align AHB burst for packets larger than 64 bytes + */ + writel((USB_SBUSCFG_BAWR_ALIGN_64B << USB_SBUSCFG_BAWR_OFF) | + (USB_SBUSCFG_BARD_ALIGN_64B << USB_SBUSCFG_BARD_OFF) | + (USB_SBUSCFG_AHBBRST_INCR16 << USB_SBUSCFG_AHBBRST_OFF), + priv->hcd_base + USB2_SBUSCFG_OFF); + + mdelay(50); +} + +static struct ehci_ops marvell_ehci_ops = { + .powerup_fixup = NULL, +}; + static int ehci_mvebu_probe(struct udevice *dev) { struct ehci_mvebu_priv *priv = dev_get_priv(dev); @@ -81,21 +114,33 @@ static int ehci_mvebu_probe(struct udevice *dev) return -ENXIO; } - usb_brg_adrdec_setup(priv->hcd_base); + /* + * For SoCs without hlock like Armada3700 we need to program the sbuscfg + * reg to guarantee AHB master's burst will not overrun or underrun + * the FIFO. Otherwise all USB2 write option will fail. + * Also, the address decoder doesn't need to get setup with this + * SoC, so don't call usb_brg_adrdec_setup(). + */ + if (of_device_is_compatible(dev, "marvell,armada3700-ehci")) + marvell_ehci_ops.powerup_fixup = marvell_ehci_powerup_fixup; + else + usb_brg_adrdec_setup((void *)priv->hcd_base); hccr = (struct ehci_hccr *)(priv->hcd_base + 0x100); hcor = (struct ehci_hcor *) - ((u32)hccr + HC_LENGTH(ehci_readl(&hccr->cr_capbase))); + ((uintptr_t)hccr + HC_LENGTH(ehci_readl(&hccr->cr_capbase))); - debug("ehci-marvell: init hccr %x and hcor %x hc_length %d\n", - (u32)hccr, (u32)hcor, - (u32)HC_LENGTH(ehci_readl(&hccr->cr_capbase))); + debug("ehci-marvell: init hccr %lx and hcor %lx hc_length %ld\n", + (uintptr_t)hccr, (uintptr_t)hcor, + (uintptr_t)HC_LENGTH(ehci_readl(&hccr->cr_capbase))); - return ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST); + return ehci_register(dev, hccr, hcor, &marvell_ehci_ops, 0, + USB_INIT_HOST); } static const struct udevice_id ehci_usb_ids[] = { { .compatible = "marvell,orion-ehci", }, + { .compatible = "marvell,armada3700-ehci", }, { } }; -- cgit v1.1 From 3335786a982578abf9a25e4d6ce67d3416ebe15e Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Mon, 23 May 2016 11:12:05 +0200 Subject: drivers/phy: Add Marvell SerDes / PHY drivers used on Armada 3k This version is based on the Marvell U-Boot version with this patch applied as latest patch: Git ID 7f408573: "fix: comphy: cp110: add comphy initialization for usb device mode" from 2016-07-05. Signed-off-by: Stefan Roese Cc: Nadav Haklai Cc: Kostya Porotchkin Cc: Wilson Ding Cc: Victor Gu Cc: Hua Jing Cc: Terry Zhou Cc: Hanna Hawa Cc: Haim Boot --- drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/phy/marvell/Kconfig | 9 + drivers/phy/marvell/Makefile | 7 + drivers/phy/marvell/comphy.h | 139 ++++++ drivers/phy/marvell/comphy_a3700.c | 962 +++++++++++++++++++++++++++++++++++++ drivers/phy/marvell/comphy_a3700.h | 275 +++++++++++ drivers/phy/marvell/comphy_core.c | 197 ++++++++ drivers/phy/marvell/comphy_hpipe.h | 382 +++++++++++++++ drivers/phy/marvell/comphy_mux.c | 118 +++++ 10 files changed, 2092 insertions(+) create mode 100644 drivers/phy/marvell/Kconfig create mode 100644 drivers/phy/marvell/Makefile create mode 100644 drivers/phy/marvell/comphy.h create mode 100644 drivers/phy/marvell/comphy_a3700.c create mode 100644 drivers/phy/marvell/comphy_a3700.h create mode 100644 drivers/phy/marvell/comphy_core.c create mode 100644 drivers/phy/marvell/comphy_hpipe.h create mode 100644 drivers/phy/marvell/comphy_mux.c (limited to 'drivers') diff --git a/drivers/Kconfig b/drivers/Kconfig index 4c555a0..e8c9e0a 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -48,6 +48,8 @@ source "drivers/pci/Kconfig" source "drivers/pcmcia/Kconfig" +source "drivers/phy/marvell/Kconfig" + source "drivers/pinctrl/Kconfig" source "drivers/power/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index ca98273..761d0b3 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -70,6 +70,7 @@ obj-y += misc/ obj-y += pcmcia/ obj-y += dfu/ obj-$(CONFIG_X86) += pch/ +obj-y += phy/marvell/ obj-y += rtc/ obj-y += sound/ obj-y += spmi/ diff --git a/drivers/phy/marvell/Kconfig b/drivers/phy/marvell/Kconfig new file mode 100644 index 0000000..4240028 --- /dev/null +++ b/drivers/phy/marvell/Kconfig @@ -0,0 +1,9 @@ +config MVEBU_COMPHY_SUPPORT + bool "ComPhy SerDes driver" + default n + help + Choose this option to add support + for Comphy driver. + This driver passes over the lanes + and initialize the lane depends on the + type and speed. diff --git a/drivers/phy/marvell/Makefile b/drivers/phy/marvell/Makefile new file mode 100644 index 0000000..91df554 --- /dev/null +++ b/drivers/phy/marvell/Makefile @@ -0,0 +1,7 @@ +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_MVEBU_COMPHY_SUPPORT) += comphy_core.o +obj-$(CONFIG_MVEBU_COMPHY_SUPPORT) += comphy_mux.o +obj-$(CONFIG_ARMADA_3700) += comphy_a3700.o diff --git a/drivers/phy/marvell/comphy.h b/drivers/phy/marvell/comphy.h new file mode 100644 index 0000000..5c50e9c --- /dev/null +++ b/drivers/phy/marvell/comphy.h @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2015-2016 Marvell International Ltd. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _COMPHY_H_ +#define _COMPHY_H_ + +#include +#include + +#if defined(DEBUG) +#define debug_enter() printf("----> Enter %s\n", __func__); +#define debug_exit() printf("<---- Exit %s\n", __func__); +#else +#define debug_enter() +#define debug_exit() +#endif + +/* COMPHY registers */ +#define COMMON_PHY_CFG1_REG 0x0 +#define COMMON_PHY_CFG1_PWR_UP_OFFSET 1 +#define COMMON_PHY_CFG1_PWR_UP_MASK \ + (0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET) +#define COMMON_PHY_CFG1_PIPE_SELECT_OFFSET 2 +#define COMMON_PHY_CFG1_PIPE_SELECT_MASK \ + (0x1 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET) +#define COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET 13 +#define COMMON_PHY_CFG1_PWR_ON_RESET_MASK \ + (0x1 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET) +#define COMMON_PHY_CFG1_CORE_RSTN_OFFSET 14 +#define COMMON_PHY_CFG1_CORE_RSTN_MASK \ + (0x1 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET) +#define COMMON_PHY_PHY_MODE_OFFSET 15 +#define COMMON_PHY_PHY_MODE_MASK \ + (0x1 << COMMON_PHY_PHY_MODE_OFFSET) + +#define COMMON_PHY_CFG6_REG 0x14 +#define COMMON_PHY_CFG6_IF_40_SEL_OFFSET 18 +#define COMMON_PHY_CFG6_IF_40_SEL_MASK \ + (0x1 << COMMON_PHY_CFG6_IF_40_SEL_OFFSET) + +#define COMMON_SELECTOR_PHY_OFFSET 0x140 +#define COMMON_SELECTOR_PIPE_OFFSET 0x144 + +#define COMMON_PHY_SD_CTRL1 0x148 +#define COMMON_PHY_SD_CTRL1_COMPHY_0_4_PORT_OFFSET 0 +#define COMMON_PHY_SD_CTRL1_COMPHY_0_4_PORT_MASK 0xFFFF +#define COMMON_PHY_SD_CTRL1_PCIE_X4_EN_OFFSET 24 +#define COMMON_PHY_SD_CTRL1_PCIE_X4_EN_MASK \ + (0x1 << COMMON_PHY_SD_CTRL1_PCIE_X4_EN_OFFSET) +#define COMMON_PHY_SD_CTRL1_PCIE_X2_EN_OFFSET 25 +#define COMMON_PHY_SD_CTRL1_PCIE_X2_EN_MASK \ + (0x1 << COMMON_PHY_SD_CTRL1_PCIE_X2_EN_OFFSET) +#define COMMON_PHY_SD_CTRL1_RXAUI1_OFFSET 26 +#define COMMON_PHY_SD_CTRL1_RXAUI1_MASK \ + (0x1 << COMMON_PHY_SD_CTRL1_RXAUI1_OFFSET) +#define COMMON_PHY_SD_CTRL1_RXAUI0_OFFSET 27 +#define COMMON_PHY_SD_CTRL1_RXAUI0_MASK \ + (0x1 << COMMON_PHY_SD_CTRL1_RXAUI0_OFFSET) + +#define DFX_DEV_GEN_CTRL12 (MVEBU_CP0_REGS_BASE + 0x400280) +#define DFX_DEV_GEN_PCIE_CLK_SRC_OFFSET 7 +#define DFX_DEV_GEN_PCIE_CLK_SRC_MASK \ + (0x3 << DFX_DEV_GEN_PCIE_CLK_SRC_OFFSET) + +#define MAX_LANE_OPTIONS 10 +#define MAX_UTMI_PHY_COUNT 2 + +struct comphy_mux_options { + u32 type; + u32 mux_value; +}; + +struct comphy_mux_data { + u32 max_lane_values; + struct comphy_mux_options mux_values[MAX_LANE_OPTIONS]; +}; + +struct comphy_map { + u32 type; + u32 speed; + u32 invert; + bool clk_src; +}; + +struct chip_serdes_phy_config { + struct comphy_mux_data *mux_data; + int (*ptr_comphy_chip_init)(struct chip_serdes_phy_config *, + struct comphy_map *); + void __iomem *comphy_base_addr; + void __iomem *hpipe3_base_addr; + u32 comphy_lanes_count; + u32 comphy_mux_bitcount; + u32 comphy_index; +}; + +/* Register helper functions */ +void reg_set(void __iomem *addr, u32 data, u32 mask); +void reg_set_silent(void __iomem *addr, u32 data, u32 mask); +void reg_set16(void __iomem *addr, u16 data, u16 mask); +void reg_set_silent16(void __iomem *addr, u16 data, u16 mask); + +/* SoC specific init functions */ +#ifdef CONFIG_ARMADA_3700 +int comphy_a3700_init(struct chip_serdes_phy_config *ptr_chip_cfg, + struct comphy_map *serdes_map); +#else +static inline int comphy_a3700_init(struct chip_serdes_phy_config *ptr_chip_cfg, + struct comphy_map *serdes_map) +{ + /* + * This function should never be called in this configuration, so + * lets return an error here. + */ + return -1; +} +#endif +int comphy_ap806_init(struct chip_serdes_phy_config *ptr_chip_cfg, + struct comphy_map *serdes_map); +int comphy_cp110_init(struct chip_serdes_phy_config *ptr_chip_cfg, + struct comphy_map *serdes_map); + +void comphy_dedicated_phys_init(void); + +/* MUX function */ +void comphy_mux_init(struct chip_serdes_phy_config *ptr_chip_cfg, + struct comphy_map *comphy_map_data, + void __iomem *selector_base); + +void comphy_pcie_config_set(u32 comphy_max_count, + struct comphy_map *serdes_map); +void comphy_pcie_config_detect(u32 comphy_max_count, + struct comphy_map *serdes_map); +void comphy_pcie_unit_general_config(u32 pex_index); + +#endif /* _COMPHY_H_ */ + diff --git a/drivers/phy/marvell/comphy_a3700.c b/drivers/phy/marvell/comphy_a3700.c new file mode 100644 index 0000000..faa62f9 --- /dev/null +++ b/drivers/phy/marvell/comphy_a3700.c @@ -0,0 +1,962 @@ +/* + * Copyright (C) 2015-2016 Marvell International Ltd. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +#include "comphy_a3700.h" + +DECLARE_GLOBAL_DATA_PTR; + +struct sgmii_phy_init_data_fix { + u16 addr; + u16 value; +}; + +/* Changes to 40M1G25 mode data required for running 40M3G125 init mode */ +static struct sgmii_phy_init_data_fix sgmii_phy_init_fix[] = { + {0x005, 0x07CC}, {0x015, 0x0000}, {0x01B, 0x0000}, {0x01D, 0x0000}, + {0x01E, 0x0000}, {0x01F, 0x0000}, {0x020, 0x0000}, {0x021, 0x0030}, + {0x026, 0x0888}, {0x04D, 0x0152}, {0x04F, 0xA020}, {0x050, 0x07CC}, + {0x053, 0xE9CA}, {0x055, 0xBD97}, {0x071, 0x3015}, {0x076, 0x03AA}, + {0x07C, 0x0FDF}, {0x0C2, 0x3030}, {0x0C3, 0x8000}, {0x0E2, 0x5550}, + {0x0E3, 0x12A4}, {0x0E4, 0x7D00}, {0x0E6, 0x0C83}, {0x101, 0xFCC0}, + {0x104, 0x0C10} +}; + +/* 40M1G25 mode init data */ +static u16 sgmii_phy_init[512] = { + /* 0 1 2 3 4 5 6 7 */ + /*-----------------------------------------------------------*/ + /* 8 9 A B C D E F */ + 0x3110, 0xFD83, 0x6430, 0x412F, 0x82C0, 0x06FA, 0x4500, 0x6D26, /* 00 */ + 0xAFC0, 0x8000, 0xC000, 0x0000, 0x2000, 0x49CC, 0x0BC9, 0x2A52, /* 08 */ + 0x0BD2, 0x0CDE, 0x13D2, 0x0CE8, 0x1149, 0x10E0, 0x0000, 0x0000, /* 10 */ + 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x4134, 0x0D2D, 0xFFFF, /* 18 */ + 0xFFE0, 0x4030, 0x1016, 0x0030, 0x0000, 0x0800, 0x0866, 0x0000, /* 20 */ + 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, /* 28 */ + 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 30 */ + 0x0000, 0x0000, 0x000F, 0x6A62, 0x1988, 0x3100, 0x3100, 0x3100, /* 38 */ + 0x3100, 0xA708, 0x2430, 0x0830, 0x1030, 0x4610, 0xFF00, 0xFF00, /* 40 */ + 0x0060, 0x1000, 0x0400, 0x0040, 0x00F0, 0x0155, 0x1100, 0xA02A, /* 48 */ + 0x06FA, 0x0080, 0xB008, 0xE3ED, 0x5002, 0xB592, 0x7A80, 0x0001, /* 50 */ + 0x020A, 0x8820, 0x6014, 0x8054, 0xACAA, 0xFC88, 0x2A02, 0x45CF, /* 58 */ + 0x000F, 0x1817, 0x2860, 0x064F, 0x0000, 0x0204, 0x1800, 0x6000, /* 60 */ + 0x810F, 0x4F23, 0x4000, 0x4498, 0x0850, 0x0000, 0x000E, 0x1002, /* 68 */ + 0x9D3A, 0x3009, 0xD066, 0x0491, 0x0001, 0x6AB0, 0x0399, 0x3780, /* 70 */ + 0x0040, 0x5AC0, 0x4A80, 0x0000, 0x01DF, 0x0000, 0x0007, 0x0000, /* 78 */ + 0x2D54, 0x00A1, 0x4000, 0x0100, 0xA20A, 0x0000, 0x0000, 0x0000, /* 80 */ + 0x0000, 0x0000, 0x0000, 0x7400, 0x0E81, 0x1000, 0x1242, 0x0210, /* 88 */ + 0x80DF, 0x0F1F, 0x2F3F, 0x4F5F, 0x6F7F, 0x0F1F, 0x2F3F, 0x4F5F, /* 90 */ + 0x6F7F, 0x4BAD, 0x0000, 0x0000, 0x0800, 0x0000, 0x2400, 0xB651, /* 98 */ + 0xC9E0, 0x4247, 0x0A24, 0x0000, 0xAF19, 0x1004, 0x0000, 0x0000, /* A0 */ + 0x0000, 0x0013, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* A8 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* B0 */ + 0x0000, 0x0000, 0x0000, 0x0060, 0x0000, 0x0000, 0x0000, 0x0000, /* B8 */ + 0x0000, 0x0000, 0x3010, 0xFA00, 0x0000, 0x0000, 0x0000, 0x0003, /* C0 */ + 0x1618, 0x8200, 0x8000, 0x0400, 0x050F, 0x0000, 0x0000, 0x0000, /* C8 */ + 0x4C93, 0x0000, 0x1000, 0x1120, 0x0010, 0x1242, 0x1242, 0x1E00, /* D0 */ + 0x0000, 0x0000, 0x0000, 0x00F8, 0x0000, 0x0041, 0x0800, 0x0000, /* D8 */ + 0x82A0, 0x572E, 0x2490, 0x14A9, 0x4E00, 0x0000, 0x0803, 0x0541, /* E0 */ + 0x0C15, 0x0000, 0x0000, 0x0400, 0x2626, 0x0000, 0x0000, 0x4200, /* E8 */ + 0x0000, 0xAA55, 0x1020, 0x0000, 0x0000, 0x5010, 0x0000, 0x0000, /* F0 */ + 0x0000, 0x0000, 0x5000, 0x0000, 0x0000, 0x0000, 0x02F2, 0x0000, /* F8 */ + 0x101F, 0xFDC0, 0x4000, 0x8010, 0x0110, 0x0006, 0x0000, 0x0000, /*100 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*108 */ + 0x04CF, 0x0000, 0x04CF, 0x0000, 0x04CF, 0x0000, 0x04C6, 0x0000, /*110 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*118 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*120 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*128 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*130 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*138 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*140 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*148 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*150 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*158 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*160 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*168 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*170 */ + 0x0000, 0x0000, 0x0000, 0x00F0, 0x08A2, 0x3112, 0x0A14, 0x0000, /*178 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*180 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*188 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*190 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*198 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1A0 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1A8 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1B0 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1B8 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1C0 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1C8 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1D0 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1D8 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1E0 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1E8 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1F0 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 /*1F8 */ +}; + +/* + * comphy_poll_reg + * + * return: 1 on success, 0 on timeout + */ +static u32 comphy_poll_reg(void *addr, u32 val, u32 mask, u32 timeout, + u8 op_type) +{ + u32 rval = 0xDEAD; + + for (; timeout > 0; timeout--) { + if (op_type == POLL_16B_REG) + rval = readw(addr); /* 16 bit */ + else + rval = readl(addr) ; /* 32 bit */ + + if ((rval & mask) == val) + return 1; + + udelay(10000); + } + + debug("Time out waiting (%p = %#010x)\n", addr, rval); + return 0; +} + +/* + * comphy_pcie_power_up + * + * return: 1 if PLL locked (OK), 0 otherwise (FAIL) + */ +static int comphy_pcie_power_up(u32 speed, u32 invert) +{ + int ret; + + debug_enter(); + + /* + * 1. Enable max PLL. + */ + reg_set16((void __iomem *)LANE_CFG1_ADDR(PCIE), + bf_use_max_pll_rate, 0); + + /* + * 2. Select 20 bit SERDES interface. + */ + reg_set16((void __iomem *)GLOB_CLK_SRC_LO_ADDR(PCIE), + bf_cfg_sel_20b, 0); + + /* + * 3. Force to use reg setting for PCIe mode + */ + reg_set16((void __iomem *)MISC_REG1_ADDR(PCIE), + bf_sel_bits_pcie_force, 0); + + /* + * 4. Change RX wait + */ + reg_set16((void __iomem *)PWR_MGM_TIM1_ADDR(PCIE), 0x10C, 0xFFFF); + + /* + * 5. Enable idle sync + */ + reg_set16((void __iomem *)UNIT_CTRL_ADDR(PCIE), + 0x60 | rb_idle_sync_en, 0xFFFF); + + /* + * 6. Enable the output of 100M/125M/500M clock + */ + reg_set16((void __iomem *)MISC_REG0_ADDR(PCIE), + 0xA00D | rb_clk500m_en | rb_clk100m_125m_en, 0xFFFF); + + /* + * 7. Enable TX + */ + reg_set((void __iomem *)PHY_REF_CLK_ADDR, 0x1342, 0xFFFFFFFF); + + /* + * 8. Check crystal jumper setting and program the Power and PLL + * Control accordingly + */ + if (get_ref_clk() == 40) { + reg_set16((void __iomem *)PWR_PLL_CTRL_ADDR(PCIE), + 0xFC63, 0xFFFF); /* 40 MHz */ + } else { + reg_set16((void __iomem *)PWR_PLL_CTRL_ADDR(PCIE), + 0xFC62, 0xFFFF); /* 25 MHz */ + } + + /* + * 9. Override Speed_PLL value and use MAC PLL + */ + reg_set16((void __iomem *)KVCO_CAL_CTRL_ADDR(PCIE), + 0x0040 | rb_use_max_pll_rate, 0xFFFF); + + /* + * 10. Check the Polarity invert bit + */ + if (invert & PHY_POLARITY_TXD_INVERT) { + reg_set16((void __iomem *)SYNC_PATTERN_ADDR(PCIE), + phy_txd_inv, 0); + } + + if (invert & PHY_POLARITY_RXD_INVERT) { + reg_set16((void __iomem *)SYNC_PATTERN_ADDR(PCIE), + phy_rxd_inv, 0); + } + + /* + * 11. Release SW reset + */ + reg_set16((void __iomem *)GLOB_PHY_CTRL0_ADDR(PCIE), + rb_mode_core_clk_freq_sel | rb_mode_pipe_width_32, + bf_soft_rst | bf_mode_refdiv); + + /* Wait for > 55 us to allow PCLK be enabled */ + udelay(PLL_SET_DELAY_US); + + /* Assert PCLK enabled */ + ret = comphy_poll_reg((void *)LANE_STAT1_ADDR(PCIE), /* address */ + rb_txdclk_pclk_en, /* value */ + rb_txdclk_pclk_en, /* mask */ + PLL_LOCK_TIMEOUT, /* timeout */ + POLL_16B_REG); /* 16bit */ + if (ret == 0) + printf("Failed to lock PCIe PLL\n"); + + debug_exit(); + + /* Return the status of the PLL */ + return ret; +} + +/* + * comphy_sata_power_up + * + * return: 1 if PLL locked (OK), 0 otherwise (FAIL) + */ +static int comphy_sata_power_up(void) +{ + int ret; + + debug_enter(); + + /* + * 0. Swap SATA TX lines + */ + reg_set((void __iomem *)rh_vsreg_addr, + vphy_sync_pattern_reg, 0xFFFFFFFF); + reg_set((void __iomem *)rh_vsreg_data, bs_txd_inv, bs_txd_inv); + + /* + * 1. Select 40-bit data width width + */ + reg_set((void __iomem *)rh_vsreg_addr, vphy_loopback_reg0, 0xFFFFFFFF); + reg_set((void __iomem *)rh_vsreg_data, 0x800, bs_phyintf_40bit); + + /* + * 2. Select reference clock and PHY mode (SATA) + */ + reg_set((void __iomem *)rh_vsreg_addr, vphy_power_reg0, 0xFFFFFFFF); + if (get_ref_clk() == 40) { + reg_set((void __iomem *)rh_vsreg_data, + 0x3, 0x00FF); /* 40 MHz */ + } else { + reg_set((void __iomem *)rh_vsreg_data, + 0x1, 0x00FF); /* 25 MHz */ + } + + /* + * 3. Use maximum PLL rate (no power save) + */ + reg_set((void __iomem *)rh_vsreg_addr, vphy_calctl_reg, 0xFFFFFFFF); + reg_set((void __iomem *)rh_vsreg_data, + bs_max_pll_rate, bs_max_pll_rate); + + /* + * 4. Reset reserved bit (??) + */ + reg_set((void __iomem *)rh_vsreg_addr, vphy_reserve_reg, 0xFFFFFFFF); + reg_set((void __iomem *)rh_vsreg_data, 0, bs_phyctrl_frm_pin); + + /* + * 5. Set vendor-specific configuration (??) + */ + reg_set((void __iomem *)rh_vs0_a, vsata_ctrl_reg, 0xFFFFFFFF); + reg_set((void __iomem *)rh_vs0_d, bs_phy_pu_pll, bs_phy_pu_pll); + + /* Wait for > 55 us to allow PLL be enabled */ + udelay(PLL_SET_DELAY_US); + + /* Assert SATA PLL enabled */ + reg_set((void __iomem *)rh_vsreg_addr, vphy_loopback_reg0, 0xFFFFFFFF); + ret = comphy_poll_reg((void *)rh_vsreg_data, /* address */ + bs_pll_ready_tx, /* value */ + bs_pll_ready_tx, /* mask */ + PLL_LOCK_TIMEOUT, /* timeout */ + POLL_32B_REG); /* 32bit */ + if (ret == 0) + printf("Failed to lock SATA PLL\n"); + + debug_exit(); + + return ret; +} + +/* + * comphy_usb3_power_up + * + * return: 1 if PLL locked (OK), 0 otherwise (FAIL) + */ +static int comphy_usb3_power_up(u32 type, u32 speed, u32 invert) +{ + int ret; + + debug_enter(); + + /* + * 1. Power up OTG module + */ + reg_set((void __iomem *)USB2_PHY_OTG_CTRL_ADDR, rb_pu_otg, 0); + + /* + * 2. Set counter for 100us pulse in USB3 Host and Device + * restore default burst size limit (Reference Clock 31:24) + */ + reg_set((void __iomem *)USB3_CTRPUL_VAL_REG, + 0x8 << 24, rb_usb3_ctr_100ns); + + + /* 0xd005c300 = 0x1001 */ + /* set PRD_TXDEEMPH (3.5db de-emph) */ + reg_set16((void __iomem *)LANE_CFG0_ADDR(USB3), 0x1, 0xFF); + + /* + * unset BIT0: set Tx Electrical Idle Mode: Transmitter is in + * low impedance mode during electrical idle + */ + /* unset BIT4: set G2 Tx Datapath with no Delayed Latency */ + /* unset BIT6: set Tx Detect Rx Mode at LoZ mode */ + reg_set16((void __iomem *)LANE_CFG1_ADDR(USB3), 0x0, 0xFFFF); + + + /* 0xd005c310 = 0x93: set Spread Spectrum Clock Enabled */ + reg_set16((void __iomem *)LANE_CFG4_ADDR(USB3), + bf_spread_spectrum_clock_en, 0x80); + + /* + * set Override Margining Controls From the MAC: Use margining signals + * from lane configuration + */ + reg_set16((void __iomem *)TEST_MODE_CTRL_ADDR(USB3), + rb_mode_margin_override, 0xFFFF); + + /* set Lane-to-Lane Bundle Clock Sampling Period = per PCLK cycles */ + /* set Mode Clock Source = PCLK is generated from REFCLK */ + reg_set16((void __iomem *)GLOB_CLK_SRC_LO_ADDR(USB3), 0x0, 0xFF); + + /* set G2 Spread Spectrum Clock Amplitude at 4K */ + reg_set16((void __iomem *)GEN2_SETTING_2_ADDR(USB3), g2_tx_ssc_amp, + 0xF000); + + /* + * unset G3 Spread Spectrum Clock Amplitude & set G3 TX and RX Register + * Master Current Select + */ + reg_set16((void __iomem *)GEN2_SETTING_3_ADDR(USB3), 0x0, 0xFFFF); + + /* + * 3. Check crystal jumper setting and program the Power and PLL + * Control accordingly + */ + if (get_ref_clk() == 40) { + reg_set16((void __iomem *)PWR_PLL_CTRL_ADDR(USB3), 0xFCA3, + 0xFFFF); /* 40 MHz */ + } else { + reg_set16((void __iomem *)PWR_PLL_CTRL_ADDR(USB3), 0xFCA2, + 0xFFFF); /* 25 MHz */ + } + + /* + * 4. Change RX wait + */ + reg_set16((void __iomem *)PWR_MGM_TIM1_ADDR(USB3), 0x10C, 0xFFFF); + + /* + * 5. Enable idle sync + */ + reg_set16((void __iomem *)UNIT_CTRL_ADDR(USB3), 0x60 | rb_idle_sync_en, + 0xFFFF); + + /* + * 6. Enable the output of 500M clock + */ + reg_set16((void __iomem *)MISC_REG0_ADDR(USB3), 0xA00D | rb_clk500m_en, + 0xFFFF); + + /* + * 7. Set 20-bit data width + */ + reg_set16((void __iomem *)DIG_LB_EN_ADDR(USB3), 0x0400, 0xFFFF); + + /* + * 8. Override Speed_PLL value and use MAC PLL + */ + reg_set16((void __iomem *)KVCO_CAL_CTRL_ADDR(USB3), + 0x0040 | rb_use_max_pll_rate, 0xFFFF); + + /* + * 9. Check the Polarity invert bit + */ + if (invert & PHY_POLARITY_TXD_INVERT) { + reg_set16((void __iomem *)SYNC_PATTERN_ADDR(USB3), + phy_txd_inv, 0); + } + + if (invert & PHY_POLARITY_RXD_INVERT) { + reg_set16((void __iomem *)SYNC_PATTERN_ADDR(USB3), + phy_rxd_inv, 0); + } + + /* + * 10. Release SW reset + */ + reg_set16((void __iomem *)GLOB_PHY_CTRL0_ADDR(USB3), + rb_mode_core_clk_freq_sel | rb_mode_pipe_width_32 | 0x20, + 0xFFFF); + + /* Wait for > 55 us to allow PCLK be enabled */ + udelay(PLL_SET_DELAY_US); + + /* Assert PCLK enabled */ + ret = comphy_poll_reg((void *)LANE_STAT1_ADDR(USB3), /* address */ + rb_txdclk_pclk_en, /* value */ + rb_txdclk_pclk_en, /* mask */ + PLL_LOCK_TIMEOUT, /* timeout */ + POLL_16B_REG); /* 16bit */ + if (ret == 0) + printf("Failed to lock USB3 PLL\n"); + + /* + * Set Soft ID for Host mode (Device mode works with Hard ID + * detection) + */ + if (type == PHY_TYPE_USB3_HOST0) { + /* + * set BIT0: set ID_MODE of Host/Device = "Soft ID" (BIT1) + * clear BIT1: set SOFT_ID = Host + * set BIT4: set INT_MODE = ID. Interrupt Mode: enable + * interrupt by ID instead of using both interrupts + * of HOST and Device ORed simultaneously + * INT_MODE=ID in order to avoid unexpected + * behaviour or both interrupts together + */ + reg_set((void __iomem *)USB32_CTRL_BASE, + usb32_ctrl_id_mode | usb32_ctrl_int_mode, + usb32_ctrl_id_mode | usb32_ctrl_soft_id | + usb32_ctrl_int_mode); + } + + debug_exit(); + + return ret; +} + +/* + * comphy_usb2_power_up + * + * return: 1 if PLL locked (OK), 0 otherwise (FAIL) + */ +static int comphy_usb2_power_up(u8 usb32) +{ + int ret; + + debug_enter(); + + if (usb32 != 0 && usb32 != 1) { + printf("invalid usb32 value: (%d), should be either 0 or 1\n", + usb32); + debug_exit(); + return 0; + } + + /* + * 0. Setup PLL. 40MHz clock uses defaults. + * See "PLL Settings for Typical REFCLK" table + */ + if (get_ref_clk() == 25) { + reg_set((void __iomem *)USB2_PHY_BASE(usb32), + 5 | (96 << 16), 0x3F | (0xFF << 16) | (0x3 << 28)); + } + + /* + * 1. PHY pull up and disable USB2 suspend + */ + reg_set((void __iomem *)USB2_PHY_CTRL_ADDR(usb32), + RB_USB2PHY_SUSPM(usb32) | RB_USB2PHY_PU(usb32), 0); + + if (usb32 != 0) { + /* + * 2. Power up OTG module + */ + reg_set((void __iomem *)USB2_PHY_OTG_CTRL_ADDR, rb_pu_otg, 0); + + /* + * 3. Configure PHY charger detection + */ + reg_set((void __iomem *)USB2_PHY_CHRGR_DET_ADDR, 0, + rb_cdp_en | rb_dcp_en | rb_pd_en | rb_cdp_dm_auto | + rb_enswitch_dp | rb_enswitch_dm | rb_pu_chrg_dtc); + } + + /* Assert PLL calibration done */ + ret = comphy_poll_reg((void *)USB2_PHY_CAL_CTRL_ADDR(usb32), + rb_usb2phy_pllcal_done, /* value */ + rb_usb2phy_pllcal_done, /* mask */ + PLL_LOCK_TIMEOUT, /* timeout */ + POLL_32B_REG); /* 32bit */ + if (ret == 0) + printf("Failed to end USB2 PLL calibration\n"); + + /* Assert impedance calibration done */ + ret = comphy_poll_reg((void *)USB2_PHY_CAL_CTRL_ADDR(usb32), + rb_usb2phy_impcal_done, /* value */ + rb_usb2phy_impcal_done, /* mask */ + PLL_LOCK_TIMEOUT, /* timeout */ + POLL_32B_REG); /* 32bit */ + if (ret == 0) + printf("Failed to end USB2 impedance calibration\n"); + + /* Assert squetch calibration done */ + ret = comphy_poll_reg((void *)USB2_PHY_RX_CHAN_CTRL1_ADDR(usb32), + rb_usb2phy_sqcal_done, /* value */ + rb_usb2phy_sqcal_done, /* mask */ + PLL_LOCK_TIMEOUT, /* timeout */ + POLL_32B_REG); /* 32bit */ + if (ret == 0) + printf("Failed to end USB2 unknown calibration\n"); + + /* Assert PLL is ready */ + ret = comphy_poll_reg((void *)USB2_PHY_PLL_CTRL0_ADDR(usb32), + rb_usb2phy_pll_ready, /* value */ + rb_usb2phy_pll_ready, /* mask */ + PLL_LOCK_TIMEOUT, /* timeout */ + POLL_32B_REG); /* 32bit */ + + if (ret == 0) + printf("Failed to lock USB2 PLL\n"); + + debug_exit(); + + return ret; +} + +/* + * comphy_emmc_power_up + * + * return: 1 if PLL locked (OK), 0 otherwise (FAIL) + */ +static int comphy_emmc_power_up(void) +{ + debug_enter(); + + /* + * 1. Bus power ON, Bus voltage 1.8V + */ + reg_set((void __iomem *)SDIO_HOST_CTRL1_ADDR, 0xB00, 0xF00); + + /* + * 2. Set FIFO parameters + */ + reg_set((void __iomem *)SDIO_SDHC_FIFO_ADDR, 0x315, 0xFFFFFFFF); + + /* + * 3. Set Capabilities 1_2 + */ + reg_set((void __iomem *)SDIO_CAP_12_ADDR, 0x25FAC8B2, 0xFFFFFFFF); + + /* + * 4. Set Endian + */ + reg_set((void __iomem *)SDIO_ENDIAN_ADDR, 0x00c00000, 0); + + /* + * 4. Init PHY + */ + reg_set((void __iomem *)SDIO_PHY_TIMING_ADDR, 0x80000000, 0x80000000); + reg_set((void __iomem *)SDIO_PHY_PAD_CTRL0_ADDR, 0x50000000, + 0xF0000000); + + /* + * 5. DLL reset + */ + reg_set((void __iomem *)SDIO_DLL_RST_ADDR, 0xFFFEFFFF, 0); + reg_set((void __iomem *)SDIO_DLL_RST_ADDR, 0x00010000, 0); + + debug_exit(); + + return 1; +} + +/* + * comphy_sgmii_power_up + * + * return: + */ +static void comphy_sgmii_phy_init(u32 lane, u32 speed) +{ + const int fix_arr_sz = ARRAY_SIZE(sgmii_phy_init_fix); + int addr, fix_idx; + u16 val; + + fix_idx = 0; + for (addr = 0; addr < 512; addr++) { + /* + * All PHY register values are defined in full for 3.125Gbps + * SERDES speed. The values required for 1.25 Gbps are almost + * the same and only few registers should be "fixed" in + * comparison to 3.125 Gbps values. These register values are + * stored in "sgmii_phy_init_fix" array. + */ + if ((speed != PHY_SPEED_1_25G) && + (sgmii_phy_init_fix[fix_idx].addr == addr)) { + /* Use new value */ + val = sgmii_phy_init_fix[fix_idx].value; + if (fix_idx < fix_arr_sz) + fix_idx++; + } else { + val = sgmii_phy_init[addr]; + } + + phy_write16(lane, addr, val, 0xFFFF); + } +} + +/* + * comphy_sgmii_power_up + * + * return: 1 if PLL locked (OK), 0 otherwise (FAIL) + */ +static int comphy_sgmii_power_up(u32 lane, u32 speed, u32 invert) +{ + int ret; + + debug_enter(); + + /* + * 1. Configure PHY to SATA/SAS mode by setting pin PIN_PIPE_SEL=0 + */ + reg_set((void __iomem *)COMPHY_SEL_ADDR, 0, rf_compy_select(lane)); + + /* + * 2. Reset PHY by setting PHY input port PIN_RESET=1. + * 3. Set PHY input port PIN_TX_IDLE=1, PIN_PU_IVREF=1 to keep + * PHY TXP/TXN output to idle state during PHY initialization + * 4. Set PHY input port PIN_PU_PLL=0, PIN_PU_RX=0, PIN_PU_TX=0. + */ + reg_set((void __iomem *)COMPHY_PHY_CFG1_ADDR(lane), + rb_pin_reset_comphy | rb_pin_tx_idle | rb_pin_pu_iveref, + rb_pin_reset_core | rb_pin_pu_pll | + rb_pin_pu_rx | rb_pin_pu_tx); + + /* + * 5. Release reset to the PHY by setting PIN_RESET=0. + */ + reg_set((void __iomem *)COMPHY_PHY_CFG1_ADDR(lane), + 0, rb_pin_reset_comphy); + + /* + * 7. Set PIN_PHY_GEN_TX[3:0] and PIN_PHY_GEN_RX[3:0] to decide + * COMPHY bit rate + */ + if (speed == PHY_SPEED_3_125G) { /* 3.125 GHz */ + reg_set((void __iomem *)COMPHY_PHY_CFG1_ADDR(lane), + (0x8 << rf_gen_rx_sel_shift) | + (0x8 << rf_gen_tx_sel_shift), + rf_gen_rx_select | rf_gen_tx_select); + + } else if (speed == PHY_SPEED_1_25G) { /* 1.25 GHz */ + reg_set((void __iomem *)COMPHY_PHY_CFG1_ADDR(lane), + (0x6 << rf_gen_rx_sel_shift) | + (0x6 << rf_gen_tx_sel_shift), + rf_gen_rx_select | rf_gen_tx_select); + } else { + printf("Unsupported COMPHY speed!\n"); + return 0; + } + + /* + * 8. Wait 1mS for bandgap and reference clocks to stabilize; + * then start SW programming. + */ + mdelay(10); + + /* 9. Program COMPHY register PHY_MODE */ + phy_write16(lane, PHY_PWR_PLL_CTRL_ADDR, + PHY_MODE_SGMII << rf_phy_mode_shift, rf_phy_mode_mask); + + /* + * 10. Set COMPHY register REFCLK_SEL to select the correct REFCLK + * source + */ + phy_write16(lane, PHY_MISC_REG0_ADDR, 0, rb_ref_clk_sel); + + /* + * 11. Set correct reference clock frequency in COMPHY register + * REF_FREF_SEL. + */ + if (get_ref_clk() == 40) { + phy_write16(lane, PHY_PWR_PLL_CTRL_ADDR, + 0x4 << rf_ref_freq_sel_shift, rf_ref_freq_sel_mask); + } else { + /* 25MHz */ + phy_write16(lane, PHY_PWR_PLL_CTRL_ADDR, + 0x1 << rf_ref_freq_sel_shift, rf_ref_freq_sel_mask); + } + + /* 12. Program COMPHY register PHY_GEN_MAX[1:0] */ + /* + * This step is mentioned in the flow received from verification team. + * However the PHY_GEN_MAX value is only meaningful for other + * interfaces (not SGMII). For instance, it selects SATA speed + * 1.5/3/6 Gbps or PCIe speed 2.5/5 Gbps + */ + + /* + * 13. Program COMPHY register SEL_BITS to set correct parallel data + * bus width + */ + /* 10bit */ + phy_write16(lane, PHY_DIG_LB_EN_ADDR, 0, rf_data_width_mask); + + /* + * 14. As long as DFE function needs to be enabled in any mode, + * COMPHY register DFE_UPDATE_EN[5:0] shall be programmed to 0x3F + * for real chip during COMPHY power on. + */ + /* + * The step 14 exists (and empty) in the original initialization flow + * obtained from the verification team. According to the functional + * specification DFE_UPDATE_EN already has the default value 0x3F + */ + + /* + * 15. Program COMPHY GEN registers. + * These registers should be programmed based on the lab testing + * result to achieve optimal performance. Please contact the CEA + * group to get the related GEN table during real chip bring-up. + * We only requred to run though the entire registers programming + * flow defined by "comphy_sgmii_phy_init" when the REF clock is + * 40 MHz. For REF clock 25 MHz the default values stored in PHY + * registers are OK. + */ + debug("Running C-DPI phy init %s mode\n", + speed == PHY_SPEED_3_125G ? "2G5" : "1G"); + if (get_ref_clk() == 40) + comphy_sgmii_phy_init(lane, speed); + + /* + * 16. [Simulation Only] should not be used for real chip. + * By pass power up calibration by programming EXT_FORCE_CAL_DONE + * (R02h[9]) to 1 to shorten COMPHY simulation time. + */ + /* + * 17. [Simulation Only: should not be used for real chip] + * Program COMPHY register FAST_DFE_TIMER_EN=1 to shorten RX + * training simulation time. + */ + + /* + * 18. Check the PHY Polarity invert bit + */ + if (invert & PHY_POLARITY_TXD_INVERT) + phy_write16(lane, PHY_SYNC_PATTERN_ADDR, phy_txd_inv, 0); + + if (invert & PHY_POLARITY_RXD_INVERT) + phy_write16(lane, PHY_SYNC_PATTERN_ADDR, phy_rxd_inv, 0); + + /* + * 19. Set PHY input ports PIN_PU_PLL, PIN_PU_TX and PIN_PU_RX to 1 + * to start PHY power up sequence. All the PHY register + * programming should be done before PIN_PU_PLL=1. There should be + * no register programming for normal PHY operation from this point. + */ + reg_set((void __iomem *)COMPHY_PHY_CFG1_ADDR(lane), + rb_pin_pu_pll | rb_pin_pu_rx | rb_pin_pu_tx, + rb_pin_pu_pll | rb_pin_pu_rx | rb_pin_pu_tx); + + /* + * 20. Wait for PHY power up sequence to finish by checking output ports + * PIN_PLL_READY_TX=1 and PIN_PLL_READY_RX=1. + */ + ret = comphy_poll_reg((void *)COMPHY_PHY_STAT1_ADDR(lane), /* address */ + rb_pll_ready_tx | rb_pll_ready_rx, /* value */ + rb_pll_ready_tx | rb_pll_ready_rx, /* mask */ + PLL_LOCK_TIMEOUT, /* timeout */ + POLL_32B_REG); /* 32bit */ + if (ret == 0) + printf("Failed to lock PLL for SGMII PHY %d\n", lane); + + /* + * 21. Set COMPHY input port PIN_TX_IDLE=0 + */ + reg_set((void __iomem *)COMPHY_PHY_CFG1_ADDR(lane), + 0x0, rb_pin_tx_idle); + + /* + * 22. After valid data appear on PIN_RXDATA bus, set PIN_RX_INIT=1. + * to start RX initialization. PIN_RX_INIT_DONE will be cleared to + * 0 by the PHY. After RX initialization is done, PIN_RX_INIT_DONE + * will be set to 1 by COMPHY. Set PIN_RX_INIT=0 after + * PIN_RX_INIT_DONE= 1. + * Please refer to RX initialization part for details. + */ + reg_set((void __iomem *)COMPHY_PHY_CFG1_ADDR(lane), rb_phy_rx_init, + 0x0); + + ret = comphy_poll_reg((void *)COMPHY_PHY_STAT1_ADDR(lane), /* address */ + rb_rx_init_done, /* value */ + rb_rx_init_done, /* mask */ + PLL_LOCK_TIMEOUT, /* timeout */ + POLL_32B_REG); /* 32bit */ + if (ret == 0) + printf("Failed to init RX of SGMII PHY %d\n", lane); + + debug_exit(); + + return ret; +} + +void comphy_dedicated_phys_init(void) +{ + int node, usb32, ret = 1; + const void *blob = gd->fdt_blob; + + debug_enter(); + + for (usb32 = 0; usb32 <= 1; usb32++) { + /* + * There are 2 UTMI PHYs in this SOC. + * One is independendent and one is paired with USB3 port (OTG) + */ + if (usb32 == 0) { + node = fdt_node_offset_by_compatible( + blob, -1, "marvell,armada-3700-ehci"); + } else { + node = fdt_node_offset_by_compatible( + blob, -1, "marvell,armada3700-xhci"); + } + + if (node > 0) { + if (fdtdec_get_is_enabled(blob, node)) { + ret = comphy_usb2_power_up(usb32); + if (ret == 0) + printf("Failed to initialize UTMI PHY\n"); + else + debug("UTMI PHY init succeed\n"); + } else { + debug("USB%d node is disabled\n", + usb32 == 0 ? 2 : 3); + } + } else { + debug("No USB%d node in DT\n", usb32 == 0 ? 2 : 3); + } + } + + node = fdt_node_offset_by_compatible(blob, -1, + "marvell,armada-3700-ahci"); + if (node > 0) { + if (fdtdec_get_is_enabled(blob, node)) { + ret = comphy_sata_power_up(); + if (ret == 0) + printf("Failed to initialize SATA PHY\n"); + else + debug("SATA PHY init succeed\n"); + } else { + debug("SATA node is disabled\n"); + } + } else { + debug("No SATA node in DT\n"); + } + + node = fdt_node_offset_by_compatible(blob, -1, + "marvell,armada-3700-sdio"); + if (node <= 0) { + debug("No SDIO node in DT, looking for MMC one\n"); + node = fdt_node_offset_by_compatible(blob, -1, + "marvell,xenon-sdhci"); + } + + if (node > 0) { + if (fdtdec_get_is_enabled(blob, node)) { + ret = comphy_emmc_power_up(); + if (ret == 0) + printf("Failed to initialize SDIO/eMMC PHY\n"); + else + debug("SDIO/eMMC PHY init succeed\n"); + } else { + debug("SDIO/eMMC node is disabled\n"); + } + } else { + debug("No SDIO/eMMC node in DT\n"); + } + + debug_exit(); +} + +int comphy_a3700_init(struct chip_serdes_phy_config *chip_cfg, + struct comphy_map *serdes_map) +{ + struct comphy_map *comphy_map; + u32 comphy_max_count = chip_cfg->comphy_lanes_count; + u32 lane, ret = 0; + + debug_enter(); + + for (lane = 0, comphy_map = serdes_map; lane < comphy_max_count; + lane++, comphy_map++) { + debug("Initialize serdes number %d\n", lane); + debug("Serdes type = 0x%x invert=%d\n", + comphy_map->type, comphy_map->invert); + + switch (comphy_map->type) { + case PHY_TYPE_UNCONNECTED: + continue; + break; + + case PHY_TYPE_PEX0: + ret = comphy_pcie_power_up(comphy_map->speed, + comphy_map->invert); + break; + + case PHY_TYPE_USB3_HOST0: + case PHY_TYPE_USB3_DEVICE: + ret = comphy_usb3_power_up(comphy_map->type, + comphy_map->speed, + comphy_map->invert); + break; + + case PHY_TYPE_SGMII0: + case PHY_TYPE_SGMII1: + ret = comphy_sgmii_power_up(lane, comphy_map->speed, + comphy_map->invert); + break; + + default: + debug("Unknown SerDes type, skip initialize SerDes %d\n", + lane); + ret = 1; + break; + } + if (ret == 0) + printf("PLL is not locked - Failed to initialize lane %d\n", + lane); + } + + debug_exit(); + return ret; +} diff --git a/drivers/phy/marvell/comphy_a3700.h b/drivers/phy/marvell/comphy_a3700.h new file mode 100644 index 0000000..eb2ed7b --- /dev/null +++ b/drivers/phy/marvell/comphy_a3700.h @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2015-2016 Marvell International Ltd. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _COMPHY_A3700_H_ +#define _COMPHY_A3700_H_ + +#include "comphy.h" +#include "comphy_hpipe.h" + +#define MVEBU_REG(offs) ((uintptr_t)MVEBU_REGISTER(offs)) + +#define DEFAULT_REFCLK_MHZ 25 +#define PLL_SET_DELAY_US 600 +#define PLL_LOCK_TIMEOUT 1000 +#define POLL_16B_REG 1 +#define POLL_32B_REG 0 + +/* + * COMPHY SB definitions + */ +#define COMPHY_SEL_ADDR MVEBU_REG(0x0183FC) +#define rf_compy_select(lane) (0x1 << (((lane) == 1) ? 4 : 0)) + +#define COMPHY_PHY_CFG1_ADDR(lane) MVEBU_REG(0x018300 + (lane) * 0x28) +#define rb_pin_pu_iveref BIT(1) +#define rb_pin_reset_core BIT(11) +#define rb_pin_reset_comphy BIT(12) +#define rb_pin_pu_pll BIT(16) +#define rb_pin_pu_rx BIT(17) +#define rb_pin_pu_tx BIT(18) +#define rb_pin_tx_idle BIT(19) +#define rf_gen_rx_sel_shift 22 +#define rf_gen_rx_select (0xFF << rf_gen_rx_sel_shift) +#define rf_gen_tx_sel_shift 26 +#define rf_gen_tx_select (0xFF << rf_gen_tx_sel_shift) +#define rb_phy_rx_init BIT(30) + +#define COMPHY_PHY_STAT1_ADDR(lane) MVEBU_REG(0x018318 + (lane) * 0x28) +#define rb_rx_init_done BIT(0) +#define rb_pll_ready_rx BIT(2) +#define rb_pll_ready_tx BIT(3) + +/* + * PCIe/USB/SGMII definitions + */ +#define PCIE_BASE MVEBU_REG(0x070000) +#define PCIETOP_BASE MVEBU_REG(0x080000) +#define PCIE_RAMBASE MVEBU_REG(0x08C000) +#define PCIEPHY_BASE MVEBU_REG(0x01F000) +#define PCIEPHY_SHFT 2 + +#define USB32_BASE MVEBU_REG(0x050000) /* usb3 device */ +#define USB32H_BASE MVEBU_REG(0x058000) /* usb3 host */ +#define USB3PHY_BASE MVEBU_REG(0x05C000) +#define USB2PHY_BASE MVEBU_REG(0x05D000) +#define USB2PHY2_BASE MVEBU_REG(0x05F000) +#define USB32_CTRL_BASE MVEBU_REG(0x05D800) +#define USB3PHY_SHFT 2 + +#define SGMIIPHY_BASE(l) (l == 1 ? USB3PHY_BASE : PCIEPHY_BASE) +#define SGMIIPHY_ADDR(l, a) (((a & 0x00007FF) * 2) | SGMIIPHY_BASE(l)) + +#define phy_read16(l, a) read16((void __iomem *)SGMIIPHY_ADDR(l, a)) +#define phy_write16(l, a, data, mask) \ + reg_set16((void __iomem *)SGMIIPHY_ADDR(l, a), data, mask) + +/* units */ +#define PCIE 1 +#define USB3 2 + +#define PHY_BASE(unit) ((unit == PCIE) ? PCIEPHY_BASE : USB3PHY_BASE) +#define PHY_SHFT(unit) ((unit == PCIE) ? PCIEPHY_SHFT : USB3PHY_SHFT) + +/* bit definition for USB32_CTRL_BASE (USB32 Control Mode) */ +#define usb32_ctrl_id_mode BIT(0) +#define usb32_ctrl_soft_id BIT(1) +#define usb32_ctrl_int_mode BIT(4) + + +#define PHY_PWR_PLL_CTRL_ADDR 0x01 /* for phy_read16 and phy_write16 */ +#define PWR_PLL_CTRL_ADDR(unit) \ + (PHY_PWR_PLL_CTRL_ADDR * PHY_SHFT(unit) + PHY_BASE(unit)) +#define rf_phy_mode_shift 5 +#define rf_phy_mode_mask (0x7 << rf_phy_mode_shift) +#define rf_ref_freq_sel_shift 0 +#define rf_ref_freq_sel_mask (0x1F << rf_ref_freq_sel_shift) +#define PHY_MODE_SGMII 0x4 + +/* for phy_read16 and phy_write16 */ +#define PHY_REG_KVCO_CAL_CTRL_ADDR 0x02 +#define KVCO_CAL_CTRL_ADDR(unit) \ + (PHY_REG_KVCO_CAL_CTRL_ADDR * PHY_SHFT(unit) + PHY_BASE(unit)) +#define rb_use_max_pll_rate BIT(12) +#define rb_force_calibration_done BIT(9) + +/* for phy_read16 and phy_write16 */ +#define PHY_DIG_LB_EN_ADDR 0x23 +#define DIG_LB_EN_ADDR(unit) \ + (PHY_DIG_LB_EN_ADDR * PHY_SHFT(unit) + PHY_BASE(unit)) +#define rf_data_width_shift 10 +#define rf_data_width_mask (0x3 << rf_data_width_shift) + +/* for phy_read16 and phy_write16 */ +#define PHY_SYNC_PATTERN_ADDR 0x24 +#define SYNC_PATTERN_ADDR(unit) \ + (PHY_SYNC_PATTERN_ADDR * PHY_SHFT(unit) + PHY_BASE(unit)) +#define phy_txd_inv BIT(10) +#define phy_rxd_inv BIT(11) + +/* for phy_read16 and phy_write16 */ +#define PHY_REG_UNIT_CTRL_ADDR 0x48 +#define UNIT_CTRL_ADDR(unit) \ + (PHY_REG_UNIT_CTRL_ADDR * PHY_SHFT(unit) + PHY_BASE(unit)) +#define rb_idle_sync_en BIT(12) + +/* for phy_read16 and phy_write16 */ +#define PHY_REG_GEN2_SETTINGS_2 0x3e +#define GEN2_SETTING_2_ADDR(unit) \ + (PHY_REG_GEN2_SETTINGS_2 * PHY_SHFT(unit) + PHY_BASE(unit)) +#define g2_tx_ssc_amp BIT(14) + +/* for phy_read16 and phy_write16 */ +#define PHY_REG_GEN2_SETTINGS_3 0x3f +#define GEN2_SETTING_3_ADDR(unit) \ + (PHY_REG_GEN2_SETTINGS_3 * PHY_SHFT(unit) + PHY_BASE(unit)) + +/* for phy_read16 and phy_write16 */ +#define PHY_MISC_REG0_ADDR 0x4f +#define MISC_REG0_ADDR(unit) \ + (PHY_MISC_REG0_ADDR * PHY_SHFT(unit) + PHY_BASE(unit)) +#define rb_clk100m_125m_en BIT(4) +#define rb_clk500m_en BIT(7) +#define rb_ref_clk_sel BIT(10) + +/* for phy_read16 and phy_write16 */ +#define PHY_REG_IFACE_REF_CLK_CTRL_ADDR 0x51 +#define UNIT_IFACE_REF_CLK_CTRL_ADDR(unit) \ + (PHY_REG_IFACE_REF_CLK_CTRL_ADDR * PHY_SHFT(unit) + PHY_BASE(unit)) +#define rb_ref1m_gen_div_force BIT(8) +#define rf_ref1m_gen_div_value_shift 0 +#define rf_ref1m_gen_div_value_mask (0xFF << rf_ref1m_gen_div_value_shift) + +/* for phy_read16 and phy_write16 */ +#define PHY_REG_ERR_CNT_CONST_CTRL_ADDR 0x6A +#define UNIT_ERR_CNT_CONST_CTRL_ADDR(unit) \ + (PHY_REG_ERR_CNT_CONST_CTRL_ADDR * PHY_SHFT(unit) + PHY_BASE(unit)) +#define rb_fast_dfe_enable BIT(13) + +#define MISC_REG1_ADDR(u) (0x73 * PHY_SHFT(u) + PHY_BASE(u)) +#define bf_sel_bits_pcie_force BIT(15) + +#define LANE_CFG0_ADDR(u) (0x180 * PHY_SHFT(u) + PHY_BASE(u)) +#define bf_use_max_pll_rate BIT(9) +#define LANE_CFG1_ADDR(u) (0x181 * PHY_SHFT(u) + PHY_BASE(u)) +#define bf_use_max_pll_rate BIT(9) +/* 0x5c310 = 0x93 (set BIT7) */ +#define LANE_CFG4_ADDR(u) (0x188 * PHY_SHFT(u) + PHY_BASE(u)) +#define bf_spread_spectrum_clock_en BIT(7) + +#define LANE_STAT1_ADDR(u) (0x183 * PHY_SHFT(u) + PHY_BASE(u)) +#define rb_txdclk_pclk_en BIT(0) + +#define GLOB_PHY_CTRL0_ADDR(u) (0x1c1 * PHY_SHFT(u) + PHY_BASE(u)) +#define bf_soft_rst BIT(0) +#define bf_mode_refdiv 0x30 +#define rb_mode_core_clk_freq_sel BIT(9) +#define rb_mode_pipe_width_32 BIT(3) + +#define TEST_MODE_CTRL_ADDR(u) (0x1c2 * PHY_SHFT(u) + PHY_BASE(u)) +#define rb_mode_margin_override BIT(2) + +#define GLOB_CLK_SRC_LO_ADDR(u) (0x1c3 * PHY_SHFT(u) + PHY_BASE(u)) +#define bf_cfg_sel_20b BIT(15) + +#define PWR_MGM_TIM1_ADDR(u) (0x1d0 * PHY_SHFT(u) + PHY_BASE(u)) + +#define PHY_REF_CLK_ADDR (0x4814 + PCIE_BASE) + +#define USB3_CTRPUL_VAL_REG (0x20 + USB32_BASE) +#define USB3H_CTRPUL_VAL_REG (0x3454 + USB32H_BASE) +#define rb_usb3_ctr_100ns 0xff000000 + +#define USB2_OTG_PHY_CTRL_ADDR (0x820 + USB2PHY_BASE) +#define rb_usb2phy_suspm BIT(14) +#define rb_usb2phy_pu BIT(0) + +#define USB2_PHY_OTG_CTRL_ADDR (0x34 + USB2PHY_BASE) +#define rb_pu_otg BIT(4) + +#define USB2_PHY_CHRGR_DET_ADDR (0x38 + USB2PHY_BASE) +#define rb_cdp_en BIT(2) +#define rb_dcp_en BIT(3) +#define rb_pd_en BIT(4) +#define rb_pu_chrg_dtc BIT(5) +#define rb_cdp_dm_auto BIT(7) +#define rb_enswitch_dp BIT(12) +#define rb_enswitch_dm BIT(13) + +#define USB2_CAL_CTRL_ADDR (0x8 + USB2PHY_BASE) +#define rb_usb2phy_pllcal_done BIT(31) +#define rb_usb2phy_impcal_done BIT(23) + +#define USB2_PLL_CTRL0_ADDR (0x0 + USB2PHY_BASE) +#define rb_usb2phy_pll_ready BIT(31) + +#define USB2_RX_CHAN_CTRL1_ADDR (0x18 + USB2PHY_BASE) +#define rb_usb2phy_sqcal_done BIT(31) + +#define USB2_PHY2_CTRL_ADDR (0x804 + USB2PHY2_BASE) +#define rb_usb2phy2_suspm BIT(7) +#define rb_usb2phy2_pu BIT(0) +#define USB2_PHY2_CAL_CTRL_ADDR (0x8 + USB2PHY2_BASE) +#define USB2_PHY2_PLL_CTRL0_ADDR (0x0 + USB2PHY2_BASE) +#define USB2_PHY2_RX_CHAN_CTRL1_ADDR (0x18 + USB2PHY2_BASE) + +#define USB2_PHY_BASE(usb32) (usb32 == 0 ? USB2PHY2_BASE : USB2PHY_BASE) +#define USB2_PHY_CTRL_ADDR(usb32) \ + (usb32 == 0 ? USB2_PHY2_CTRL_ADDR : USB2_OTG_PHY_CTRL_ADDR) +#define RB_USB2PHY_SUSPM(usb32) \ + (usb32 == 0 ? rb_usb2phy2_suspm : rb_usb2phy_suspm) +#define RB_USB2PHY_PU(usb32) \ + (usb32 == 0 ? rb_usb2phy2_pu : rb_usb2phy_pu) +#define USB2_PHY_CAL_CTRL_ADDR(usb32) \ + (usb32 == 0 ? USB2_PHY2_CAL_CTRL_ADDR : USB2_CAL_CTRL_ADDR) +#define USB2_PHY_RX_CHAN_CTRL1_ADDR(usb32) \ + (usb32 == 0 ? USB2_PHY2_RX_CHAN_CTRL1_ADDR : USB2_RX_CHAN_CTRL1_ADDR) +#define USB2_PHY_PLL_CTRL0_ADDR(usb32) \ + (usb32 == 0 ? USB2_PHY2_PLL_CTRL0_ADDR : USB2_PLL_CTRL0_ADDR) + +/* + * SATA definitions + */ +#define AHCI_BASE MVEBU_REG(0xE0000) + +#define rh_vsreg_addr (AHCI_BASE + 0x178) +#define rh_vsreg_data (AHCI_BASE + 0x17C) +#define rh_vs0_a (AHCI_BASE + 0xA0) +#define rh_vs0_d (AHCI_BASE + 0xA4) + +#define vphy_sync_pattern_reg 0x224 +#define bs_txd_inv BIT(10) +#define bs_rxd_inv BIT(11) + +#define vphy_loopback_reg0 0x223 +#define bs_phyintf_40bit 0x0C00 +#define bs_pll_ready_tx 0x10 + +#define vphy_power_reg0 0x201 + +#define vphy_calctl_reg 0x202 +#define bs_max_pll_rate BIT(12) + +#define vphy_reserve_reg 0x0e +#define bs_phyctrl_frm_pin BIT(13) + +#define vsata_ctrl_reg 0x00 +#define bs_phy_pu_pll BIT(6) + +/* + * SDIO/eMMC definitions + */ +#define SDIO_BASE MVEBU_REG(0xD8000) + +#define SDIO_HOST_CTRL1_ADDR (SDIO_BASE + 0x28) +#define SDIO_SDHC_FIFO_ADDR (SDIO_BASE + 0x12C) +#define SDIO_CAP_12_ADDR (SDIO_BASE + 0x40) +#define SDIO_ENDIAN_ADDR (SDIO_BASE + 0x1A4) +#define SDIO_PHY_TIMING_ADDR (SDIO_BASE + 0x170) +#define SDIO_PHY_PAD_CTRL0_ADDR (SDIO_BASE + 0x178) +#define SDIO_DLL_RST_ADDR (SDIO_BASE + 0x148) + +#endif /* _COMPHY_A3700_H_ */ diff --git a/drivers/phy/marvell/comphy_core.c b/drivers/phy/marvell/comphy_core.c new file mode 100644 index 0000000..67eb139 --- /dev/null +++ b/drivers/phy/marvell/comphy_core.c @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2015-2016 Marvell International Ltd. + * + * Copyright (C) 2016 Stefan Roese + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +#include "comphy.h" + +#define COMPHY_MAX_CHIP 4 + +DECLARE_GLOBAL_DATA_PTR; + +static char *get_speed_string(u32 speed) +{ + char *speed_strings[] = {"1.25 Gbps", "1.5 Gbps", "2.5 Gbps", + "3.0 Gbps", "3.125 Gbps", "5 Gbps", "6 Gbps", + "6.25 Gbps", "10.31 Gbps" }; + + if (speed < 0 || speed > PHY_SPEED_MAX) + return "invalid"; + + return speed_strings[speed]; +} + +static char *get_type_string(u32 type) +{ + char *type_strings[] = {"UNCONNECTED", "PEX0", "PEX1", "PEX2", "PEX3", + "SATA0", "SATA1", "SATA2", "SATA3", "SGMII0", + "SGMII1", "SGMII2", "SGMII3", "QSGMII", + "USB3_HOST0", "USB3_HOST1", "USB3_DEVICE", + "XAUI0", "XAUI1", "XAUI2", "XAUI3", + "RXAUI0", "RXAUI1", "KR"}; + + if (type < 0 || type > PHY_TYPE_MAX) + return "invalid"; + + return type_strings[type]; +} + +void reg_set(void __iomem *addr, u32 data, u32 mask) +{ + debug("Write to address = %#010lx, data = %#010x (mask = %#010x) - ", + (unsigned long)addr, data, mask); + debug("old value = %#010x ==> ", readl(addr)); + reg_set_silent(addr, data, mask); + debug("new value %#010x\n", readl(addr)); +} + +void reg_set_silent(void __iomem *addr, u32 data, u32 mask) +{ + u32 reg_data; + + reg_data = readl(addr); + reg_data &= ~mask; + reg_data |= data; + writel(reg_data, addr); +} + +void reg_set16(void __iomem *addr, u16 data, u16 mask) +{ + debug("Write to address = %#010lx, data = %#06x (mask = %#06x) - ", + (unsigned long)addr, data, mask); + debug("old value = %#06x ==> ", readw(addr)); + reg_set_silent16(addr, data, mask); + debug("new value %#06x\n", readw(addr)); +} + +void reg_set_silent16(void __iomem *addr, u16 data, u16 mask) +{ + u16 reg_data; + + reg_data = readw(addr); + reg_data &= ~mask; + reg_data |= data; + writew(reg_data, addr); +} + +void comphy_print(struct chip_serdes_phy_config *chip_cfg, + struct comphy_map *comphy_map_data) +{ + u32 lane; + + for (lane = 0; lane < chip_cfg->comphy_lanes_count; + lane++, comphy_map_data++) { + if (comphy_map_data->type == PHY_TYPE_UNCONNECTED) + continue; + + if (comphy_map_data->speed == PHY_SPEED_INVALID) { + printf("Comphy-%d: %-13s\n", lane, + get_type_string(comphy_map_data->type)); + } else { + printf("Comphy-%d: %-13s %-10s\n", lane, + get_type_string(comphy_map_data->type), + get_speed_string(comphy_map_data->speed)); + } + } +} + +static int comphy_probe(struct udevice *dev) +{ + const void *blob = gd->fdt_blob; + int node = dev->of_offset; + struct chip_serdes_phy_config *chip_cfg = dev_get_priv(dev); + struct comphy_map comphy_map_data[MAX_LANE_OPTIONS]; + int subnode; + int lane; + + /* Save base addresses for later use */ + chip_cfg->comphy_base_addr = (void *)dev_get_addr_index(dev, 0); + if (IS_ERR(chip_cfg->comphy_base_addr)) + return PTR_ERR(chip_cfg->comphy_base_addr); + + chip_cfg->hpipe3_base_addr = (void *)dev_get_addr_index(dev, 1); + if (IS_ERR(chip_cfg->hpipe3_base_addr)) + return PTR_ERR(chip_cfg->hpipe3_base_addr); + + chip_cfg->comphy_lanes_count = fdtdec_get_int(blob, node, + "max-lanes", 0); + if (chip_cfg->comphy_lanes_count <= 0) { + dev_err(&dev->dev, "comphy max lanes is wrong\n"); + return -EINVAL; + } + + chip_cfg->comphy_mux_bitcount = fdtdec_get_int(blob, node, + "mux-bitcount", 0); + if (chip_cfg->comphy_mux_bitcount <= 0) { + dev_err(&dev->dev, "comphy mux bit count is wrong\n"); + return -EINVAL; + } + + if (of_device_is_compatible(dev, "marvell,comphy-armada-3700")) + chip_cfg->ptr_comphy_chip_init = comphy_a3700_init; + + /* + * Bail out if no chip_init function is defined, e.g. no + * compatible node is found + */ + if (!chip_cfg->ptr_comphy_chip_init) { + dev_err(&dev->dev, "comphy: No compatible DT node found\n"); + return -ENODEV; + } + + lane = 0; + fdt_for_each_subnode(blob, subnode, node) { + /* Skip disabled ports */ + if (!fdtdec_get_is_enabled(blob, subnode)) + continue; + + comphy_map_data[lane].speed = fdtdec_get_int( + blob, subnode, "phy-speed", PHY_TYPE_INVALID); + comphy_map_data[lane].type = fdtdec_get_int( + blob, subnode, "phy-type", PHY_SPEED_INVALID); + comphy_map_data[lane].invert = fdtdec_get_int( + blob, subnode, "phy-invert", PHY_POLARITY_NO_INVERT); + comphy_map_data[lane].clk_src = fdtdec_get_bool(blob, subnode, + "clk-src"); + if (comphy_map_data[lane].type == PHY_TYPE_INVALID) { + printf("no phy type for lane %d, setting lane as unconnected\n", + lane + 1); + } + + lane++; + } + + /* Save comphy index for MultiCP devices (A8K) */ + chip_cfg->comphy_index = dev->seq; + /* PHY power UP sequence */ + chip_cfg->ptr_comphy_chip_init(chip_cfg, comphy_map_data); + /* PHY print SerDes status */ + comphy_print(chip_cfg, comphy_map_data); + + /* Initialize dedicated PHYs (not muxed SerDes lanes) */ + comphy_dedicated_phys_init(); + + return 0; +} + +static const struct udevice_id comphy_ids[] = { + { .compatible = "marvell,mvebu-comphy" }, + { } +}; + +U_BOOT_DRIVER(mvebu_comphy) = { + .name = "mvebu_comphy", + .id = UCLASS_MISC, + .of_match = comphy_ids, + .probe = comphy_probe, + .priv_auto_alloc_size = sizeof(struct chip_serdes_phy_config), +}; diff --git a/drivers/phy/marvell/comphy_hpipe.h b/drivers/phy/marvell/comphy_hpipe.h new file mode 100644 index 0000000..0c9b500 --- /dev/null +++ b/drivers/phy/marvell/comphy_hpipe.h @@ -0,0 +1,382 @@ +/* + * Copyright (C) 2015-2016 Marvell International Ltd. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _COMPHY_HPIPE_H_ +#define _COMPHY_HPIPE_H_ + +/* SerDes IP register */ +#define SD_EXTERNAL_CONFIG0_REG 0 +#define SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET 1 +#define SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK \ + (1 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET) +#define SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET 3 +#define SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_MASK \ + (0xf << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET) +#define SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET 7 +#define SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_MASK \ + (0xf << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET) +#define SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET 11 +#define SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK \ + (1 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET) +#define SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET 12 +#define SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK \ + (1 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET) +#define SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_OFFSET 14 +#define SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_MASK \ + (1 << SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_OFFSET) +#define SD_EXTERNAL_CONFIG0_MEDIA_MODE_OFFSET 15 +#define SD_EXTERNAL_CONFIG0_MEDIA_MODE_MASK \ + (0x1 << SD_EXTERNAL_CONFIG0_MEDIA_MODE_OFFSET) + +#define SD_EXTERNAL_CONFIG1_REG 0x4 +#define SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET 3 +#define SD_EXTERNAL_CONFIG1_RESET_IN_MASK \ + (0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET) +#define SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET 4 +#define SD_EXTERNAL_CONFIG1_RX_INIT_MASK \ + (0x1 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET) +#define SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET 5 +#define SD_EXTERNAL_CONFIG1_RESET_CORE_MASK \ + (0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET) +#define SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET 6 +#define SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK \ + (0x1 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET) + +#define SD_EXTERNAL_CONFIG2_REG 0x8 +#define SD_EXTERNAL_CONFIG2_PIN_DFE_EN_OFFSET 4 +#define SD_EXTERNAL_CONFIG2_PIN_DFE_EN_MASK \ + (0x1 << SD_EXTERNAL_CONFIG2_PIN_DFE_EN_OFFSET) + +#define SD_EXTERNAL_STATUS0_REG 0x18 +#define SD_EXTERNAL_STATUS0_PLL_TX_OFFSET 2 +#define SD_EXTERNAL_STATUS0_PLL_TX_MASK \ + (0x1 << SD_EXTERNAL_STATUS0_PLL_TX_OFFSET) +#define SD_EXTERNAL_STATUS0_PLL_RX_OFFSET 3 +#define SD_EXTERNAL_STATUS0_PLL_RX_MASK \ + (0x1 << SD_EXTERNAL_STATUS0_PLL_RX_OFFSET) +#define SD_EXTERNAL_STATUS0_RX_INIT_OFFSET 4 +#define SD_EXTERNAL_STATUS0_RX_INIT_MASK \ + (0x1 << SD_EXTERNAL_STATUS0_RX_INIT_OFFSET) +#define SD_EXTERNAL_STATUS0_RF_RESET_IN_OFFSET 6 +#define SD_EXTERNAL_STATUS0_RF_RESET_IN_MASK \ + (0x1 << SD_EXTERNAL_STATUS0_RF_RESET_IN_OFFSET) + +/* HPIPE register */ +#define HPIPE_PWR_PLL_REG 0x4 +#define HPIPE_PWR_PLL_REF_FREQ_OFFSET 0 +#define HPIPE_PWR_PLL_REF_FREQ_MASK \ + (0x1f << HPIPE_PWR_PLL_REF_FREQ_OFFSET) +#define HPIPE_PWR_PLL_PHY_MODE_OFFSET 5 +#define HPIPE_PWR_PLL_PHY_MODE_MASK \ + (0x7 << HPIPE_PWR_PLL_PHY_MODE_OFFSET) + +#define HPIPE_KVCO_CALIB_CTRL_REG 0x8 +#define HPIPE_KVCO_CALIB_CTRL_MAX_PLL_OFFSET 12 +#define HPIPE_KVCO_CALIB_CTRL_MAX_PLL_MASK \ + (0x1 << HPIPE_KVCO_CALIB_CTRL_MAX_PLL_OFFSET) + +#define HPIPE_SQUELCH_FFE_SETTING_REG 0x018 + +#define HPIPE_DFE_REG0 0x01C +#define HPIPE_DFE_RES_FORCE_OFFSET 15 +#define HPIPE_DFE_RES_FORCE_MASK \ + (0x1 << HPIPE_DFE_RES_FORCE_OFFSET) + +#define HPIPE_DFE_F3_F5_REG 0x028 +#define HPIPE_DFE_F3_F5_DFE_EN_OFFSET 14 +#define HPIPE_DFE_F3_F5_DFE_EN_MASK \ + (0x1 << HPIPE_DFE_F3_F5_DFE_EN_OFFSET) +#define HPIPE_DFE_F3_F5_DFE_CTRL_OFFSET 15 +#define HPIPE_DFE_F3_F5_DFE_CTRL_MASK \ + (0x1 << HPIPE_DFE_F3_F5_DFE_CTRL_OFFSET) + +#define HPIPE_G1_SET_0_REG 0x034 +#define HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET 7 +#define HPIPE_G1_SET_0_G1_TX_EMPH1_MASK \ + (0xf << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET) + +#define HPIPE_G1_SET_1_REG 0x038 +#define HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET 0 +#define HPIPE_G1_SET_1_G1_RX_SELMUPI_MASK \ + (0x7 << HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET) +#define HPIPE_G1_SET_1_G1_RX_SELMUPP_OFFSET 3 +#define HPIPE_G1_SET_1_G1_RX_SELMUPP_MASK \ + (0x7 << HPIPE_G1_SET_1_G1_RX_SELMUPP_OFFSET) +#define HPIPE_G1_SET_1_G1_RX_DFE_EN_OFFSET 10 +#define HPIPE_G1_SET_1_G1_RX_DFE_EN_MASK \ + (0x1 << HPIPE_G1_SET_1_G1_RX_DFE_EN_OFFSET) + +#define HPIPE_G2_SETTINGS_1_REG 0x040 + +#define HPIPE_G3_SETTINGS_1_REG 0x048 +#define HPIPE_G3_RX_SELMUPI_OFFSET 0 +#define HPIPE_G3_RX_SELMUPI_MASK \ + (0x7 << HPIPE_G3_RX_SELMUPI_OFFSET) +#define HPIPE_G3_RX_SELMUPF_OFFSET 3 +#define HPIPE_G3_RX_SELMUPF_MASK \ + (0x7 << HPIPE_G3_RX_SELMUPF_OFFSET) +#define HPIPE_G3_SETTING_BIT_OFFSET 13 +#define HPIPE_G3_SETTING_BIT_MASK \ + (0x1 << HPIPE_G3_SETTING_BIT_OFFSET) + +#define HPIPE_LOOPBACK_REG 0x08c +#define HPIPE_LOOPBACK_SEL_OFFSET 1 +#define HPIPE_LOOPBACK_SEL_MASK \ + (0x7 << HPIPE_LOOPBACK_SEL_OFFSET) + +#define HPIPE_SYNC_PATTERN_REG 0x090 + +#define HPIPE_INTERFACE_REG 0x94 +#define HPIPE_INTERFACE_GEN_MAX_OFFSET 10 +#define HPIPE_INTERFACE_GEN_MAX_MASK \ + (0x3 << HPIPE_INTERFACE_GEN_MAX_OFFSET) +#define HPIPE_INTERFACE_LINK_TRAIN_OFFSET 14 +#define HPIPE_INTERFACE_LINK_TRAIN_MASK \ + (0x1 << HPIPE_INTERFACE_LINK_TRAIN_OFFSET) + +#define HPIPE_ISOLATE_MODE_REG 0x98 +#define HPIPE_ISOLATE_MODE_GEN_RX_OFFSET 0 +#define HPIPE_ISOLATE_MODE_GEN_RX_MASK \ + (0xf << HPIPE_ISOLATE_MODE_GEN_RX_OFFSET) +#define HPIPE_ISOLATE_MODE_GEN_TX_OFFSET 4 +#define HPIPE_ISOLATE_MODE_GEN_TX_MASK \ + (0xf << HPIPE_ISOLATE_MODE_GEN_TX_OFFSET) + +#define HPIPE_VTHIMPCAL_CTRL_REG 0x104 + +#define HPIPE_PCIE_REG0 0x120 +#define HPIPE_PCIE_IDLE_SYNC_OFFSET 12 +#define HPIPE_PCIE_IDLE_SYNC_MASK \ + (0x1 << HPIPE_PCIE_IDLE_SYNC_OFFSET) +#define HPIPE_PCIE_SEL_BITS_OFFSET 13 +#define HPIPE_PCIE_SEL_BITS_MASK \ + (0x3 << HPIPE_PCIE_SEL_BITS_OFFSET) + +#define HPIPE_LANE_ALIGN_REG 0x124 +#define HPIPE_LANE_ALIGN_OFF_OFFSET 12 +#define HPIPE_LANE_ALIGN_OFF_MASK \ + (0x1 << HPIPE_LANE_ALIGN_OFF_OFFSET) + +#define HPIPE_MISC_REG 0x13C +#define HPIPE_MISC_CLK100M_125M_OFFSET 4 +#define HPIPE_MISC_CLK100M_125M_MASK \ + (0x1 << HPIPE_MISC_CLK100M_125M_OFFSET) +#define HPIPE_MISC_TXDCLK_2X_OFFSET 6 +#define HPIPE_MISC_TXDCLK_2X_MASK \ + (0x1 << HPIPE_MISC_TXDCLK_2X_OFFSET) +#define HPIPE_MISC_CLK500_EN_OFFSET 7 +#define HPIPE_MISC_CLK500_EN_MASK \ + (0x1 << HPIPE_MISC_CLK500_EN_OFFSET) +#define HPIPE_MISC_REFCLK_SEL_OFFSET 10 +#define HPIPE_MISC_REFCLK_SEL_MASK \ + (0x1 << HPIPE_MISC_REFCLK_SEL_OFFSET) + +#define HPIPE_RX_CONTROL_1_REG 0x140 +#define HPIPE_RX_CONTROL_1_RXCLK2X_SEL_OFFSET 11 +#define HPIPE_RX_CONTROL_1_RXCLK2X_SEL_MASK \ + (0x1 << HPIPE_RX_CONTROL_1_RXCLK2X_SEL_OFFSET) +#define HPIPE_RX_CONTROL_1_CLK8T_EN_OFFSET 12 +#define HPIPE_RX_CONTROL_1_CLK8T_EN_MASK \ + (0x1 << HPIPE_RX_CONTROL_1_CLK8T_EN_OFFSET) + +#define HPIPE_PWR_CTR_REG 0x148 +#define HPIPE_PWR_CTR_RST_DFE_OFFSET 0 +#define HPIPE_PWR_CTR_RST_DFE_MASK \ + (0x1 << HPIPE_PWR_CTR_RST_DFE_OFFSET) +#define HPIPE_PWR_CTR_SFT_RST_OFFSET 10 +#define HPIPE_PWR_CTR_SFT_RST_MASK \ + (0x1 << HPIPE_PWR_CTR_SFT_RST_OFFSET) + +#define HPIPE_PLLINTP_REG1 0x150 + +#define HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG 0x16C +#define HPIPE_SMAPLER_OFFSET 12 +#define HPIPE_SMAPLER_MASK \ + (0x1 << HPIPE_SMAPLER_OFFSET) + +#define HPIPE_PWR_CTR_DTL_REG 0x184 +#define HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET 2 +#define HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK \ + (0x1 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET) + +#define HPIPE_RX_REG3 0x188 + +#define HPIPE_TX_TRAIN_CTRL_0_REG 0x268 +#define HPIPE_TX_TRAIN_P2P_HOLD_OFFSET 15 +#define HPIPE_TX_TRAIN_P2P_HOLD_MASK \ + (0x1 << HPIPE_TX_TRAIN_P2P_HOLD_OFFSET) + +#define HPIPE_TX_TRAIN_CTRL_REG 0x26C +#define HPIPE_TX_TRAIN_CTRL_G1_OFFSET 0 +#define HPIPE_TX_TRAIN_CTRL_G1_MASK \ + (0x1 << HPIPE_TX_TRAIN_CTRL_G1_OFFSET) +#define HPIPE_TX_TRAIN_CTRL_GN1_OFFSET 1 +#define HPIPE_TX_TRAIN_CTRL_GN1_MASK \ + (0x1 << HPIPE_TX_TRAIN_CTRL_GN1_OFFSET) +#define HPIPE_TX_TRAIN_CTRL_G0_OFFSET 2 +#define HPIPE_TX_TRAIN_CTRL_G0_MASK \ + (0x1 << HPIPE_TX_TRAIN_CTRL_G0_OFFSET) + +#define HPIPE_TX_TRAIN_CTRL_4_REG 0x278 +#define HPIPE_TRX_TRAIN_TIMER_OFFSET 0 +#define HPIPE_TRX_TRAIN_TIMER_MASK \ + (0x3FF << HPIPE_TRX_TRAIN_TIMER_OFFSET) + +#define HPIPE_PCIE_REG1 0x288 +#define HPIPE_PCIE_REG3 0x290 + +#define HPIPE_TX_TRAIN_CTRL_5_REG 0x2A4 +#define HPIPE_TX_TRAIN_START_SQ_EN_OFFSET 11 +#define HPIPE_TX_TRAIN_START_SQ_EN_MASK \ + (0x1 << HPIPE_TX_TRAIN_START_SQ_EN_OFFSET) +#define HPIPE_TX_TRAIN_START_FRM_DET_EN_OFFSET 12 +#define HPIPE_TX_TRAIN_START_FRM_DET_EN_MASK \ + (0x1 << HPIPE_TX_TRAIN_START_FRM_DET_EN_OFFSET) +#define HPIPE_TX_TRAIN_START_FRM_LOCK_EN_OFFSET 13 +#define HPIPE_TX_TRAIN_START_FRM_LOCK_EN_MASK \ + (0x1 << HPIPE_TX_TRAIN_START_FRM_LOCK_EN_OFFSET) +#define HPIPE_TX_TRAIN_WAIT_TIME_EN_OFFSET 14 +#define HPIPE_TX_TRAIN_WAIT_TIME_EN_MASK \ + (0x1 << HPIPE_TX_TRAIN_WAIT_TIME_EN_OFFSET) + +#define HPIPE_TX_TRAIN_REG 0x31C +#define HPIPE_TX_TRAIN_CHK_INIT_OFFSET 4 +#define HPIPE_TX_TRAIN_CHK_INIT_MASK \ + (0x1 << HPIPE_TX_TRAIN_CHK_INIT_OFFSET) +#define HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_OFFSET 7 +#define HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_MASK \ + (0x1 << HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_OFFSET) + +#define HPIPE_TX_TRAIN_CTRL_11_REG 0x438 +#define HPIPE_TX_STATUS_CHECK_MODE_OFFSET 6 +#define HPIPE_TX_TX_STATUS_CHECK_MODE_MASK \ + (0x1 << HPIPE_TX_STATUS_CHECK_MODE_OFFSET) +#define HPIPE_TX_NUM_OF_PRESET_OFFSET 10 +#define HPIPE_TX_NUM_OF_PRESET_MASK \ + (0x7 << HPIPE_TX_NUM_OF_PRESET_OFFSET) +#define HPIPE_TX_SWEEP_PRESET_EN_OFFSET 15 +#define HPIPE_TX_SWEEP_PRESET_EN_MASK \ + (0x1 << HPIPE_TX_SWEEP_PRESET_EN_OFFSET) + +#define HPIPE_G1_SETTINGS_3_REG 0x440 + +#define HPIPE_G1_SETTINGS_4_REG 0x444 +#define HPIPE_G1_SETTINGS_4_G1_DFE_RES_OFFSET 8 +#define HPIPE_G1_SETTINGS_4_G1_DFE_RES_MASK \ + (0x3 << HPIPE_G1_SETTINGS_4_G1_DFE_RES_OFFSET) + +#define HPIPE_G2_SETTINGS_3_REG 0x448 +#define HPIPE_G2_SETTINGS_4_REG 0x44C + +#define HPIPE_G3_SETTING_3_REG 0x450 +#define HPIPE_G3_FFE_DEG_RES_LEVEL_OFFSET 12 +#define HPIPE_G3_FFE_DEG_RES_LEVEL_MASK \ + (0x3 << HPIPE_G3_FFE_DEG_RES_LEVEL_OFFSET) +#define HPIPE_G3_FFE_LOAD_RES_LEVEL_OFFSET 14 +#define HPIPE_G3_FFE_LOAD_RES_LEVEL_MASK \ + (0x3 << HPIPE_G3_FFE_LOAD_RES_LEVEL_OFFSET) + +#define HPIPE_G3_SETTING_4_REG 0x454 +#define HPIPE_G3_DFE_RES_OFFSET 8 +#define HPIPE_G3_DFE_RES_MASK \ + (0x3 << HPIPE_G3_DFE_RES_OFFSET) + +#define HPIPE_DFE_CTRL_28_REG 0x49C +#define HPIPE_DFE_CTRL_28_PIPE4_OFFSET 7 +#define HPIPE_DFE_CTRL_28_PIPE4_MASK \ + (0x1 << HPIPE_DFE_CTRL_28_PIPE4_OFFSET) + +#define HPIPE_LANE_CONFIG0_REG 0x600 +#define HPIPE_LANE_CONFIG0_TXDEEMPH0_OFFSET 0 +#define HPIPE_LANE_CONFIG0_TXDEEMPH0_MASK \ + (0x1 << HPIPE_LANE_CONFIG0_TXDEEMPH0_OFFSET) + +#define HPIPE_LANE_CONFIG1_REG 0x604 +#define HPIPE_LANE_CONFIG1_MAX_PLL_OFFSET 9 +#define HPIPE_LANE_CONFIG1_MAX_PLL_MASK \ + (0x1 << HPIPE_LANE_CONFIG1_MAX_PLL_OFFSET) +#define HPIPE_LANE_CONFIG1_GEN2_PLL_OFFSET 10 +#define HPIPE_LANE_CONFIG1_GEN2_PLL_MASK \ + (0x1 << HPIPE_LANE_CONFIG1_GEN2_PLL_OFFSET) + +#define HPIPE_LANE_STATUS1_REG 0x60C +#define HPIPE_LANE_STATUS1_PCLK_EN_OFFSET 0 +#define HPIPE_LANE_STATUS1_PCLK_EN_MASK \ + (0x1 << HPIPE_LANE_STATUS1_PCLK_EN_OFFSET) + +#define HPIPE_LANE_CFG4_REG 0x620 +#define HPIPE_LANE_CFG4_DFE_CTRL_OFFSET 0 +#define HPIPE_LANE_CFG4_DFE_CTRL_MASK \ + (0x7 << HPIPE_LANE_CFG4_DFE_CTRL_OFFSET) +#define HPIPE_LANE_CFG4_DFE_OVER_OFFSET 6 +#define HPIPE_LANE_CFG4_DFE_OVER_MASK \ + (0x1 << HPIPE_LANE_CFG4_DFE_OVER_OFFSET) +#define HPIPE_LANE_CFG4_SSC_CTRL_OFFSET 7 +#define HPIPE_LANE_CFG4_SSC_CTRL_MASK \ + (0x1 << HPIPE_LANE_CFG4_SSC_CTRL_OFFSET) + +#define HPIPE_LANE_EQU_CONFIG_0_REG 0x69C +#define HPIPE_CFG_PHY_RC_EP_OFFSET 12 +#define HPIPE_CFG_PHY_RC_EP_MASK \ + (0x1 << HPIPE_CFG_PHY_RC_EP_OFFSET) + +#define HPIPE_LANE_EQ_CFG1_REG 0x6a0 +#define HPIPE_CFG_UPDATE_POLARITY_OFFSET 12 +#define HPIPE_CFG_UPDATE_POLARITY_MASK \ + (0x1 << HPIPE_CFG_UPDATE_POLARITY_OFFSET) + +#define HPIPE_RST_CLK_CTRL_REG 0x704 +#define HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET 0 +#define HPIPE_RST_CLK_CTRL_PIPE_RST_MASK \ + (0x1 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET) +#define HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET 2 +#define HPIPE_RST_CLK_CTRL_FIXED_PCLK_MASK \ + (0x1 << HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET) +#define HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET 3 +#define HPIPE_RST_CLK_CTRL_PIPE_WIDTH_MASK \ + (0x1 << HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET) +#define HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET 9 +#define HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_MASK \ + (0x1 << HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET) + +#define HPIPE_TST_MODE_CTRL_REG 0x708 +#define HPIPE_TST_MODE_CTRL_MODE_MARGIN_OFFSET 2 +#define HPIPE_TST_MODE_CTRL_MODE_MARGIN_MASK \ + (0x1 << HPIPE_TST_MODE_CTRL_MODE_MARGIN_OFFSET) + +#define HPIPE_CLK_SRC_LO_REG 0x70c +#define HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_OFFSET 1 +#define HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_MASK \ + (0x1 << HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_OFFSET) +#define HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_OFFSET 2 +#define HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_MASK \ + (0x3 << HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_OFFSET) +#define HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET 5 +#define HPIPE_CLK_SRC_LO_PLL_RDY_DL_MASK \ + (0x7 << HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET) + +#define HPIPE_CLK_SRC_HI_REG 0x710 +#define HPIPE_CLK_SRC_HI_LANE_STRT_OFFSET 0 +#define HPIPE_CLK_SRC_HI_LANE_STRT_MASK \ + (0x1 << HPIPE_CLK_SRC_HI_LANE_STRT_OFFSET) +#define HPIPE_CLK_SRC_HI_LANE_BREAK_OFFSET 1 +#define HPIPE_CLK_SRC_HI_LANE_BREAK_MASK \ + (0x1 << HPIPE_CLK_SRC_HI_LANE_BREAK_OFFSET) +#define HPIPE_CLK_SRC_HI_LANE_MASTER_OFFSET 2 +#define HPIPE_CLK_SRC_HI_LANE_MASTER_MASK \ + (0x1 << HPIPE_CLK_SRC_HI_LANE_MASTER_OFFSET) +#define HPIPE_CLK_SRC_HI_MODE_PIPE_OFFSET 7 +#define HPIPE_CLK_SRC_HI_MODE_PIPE_MASK \ + (0x1 << HPIPE_CLK_SRC_HI_MODE_PIPE_OFFSET) + +#define HPIPE_GLOBAL_MISC_CTRL 0x718 +#define HPIPE_GLOBAL_PM_CTRL 0x740 +#define HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET 0 +#define HPIPE_GLOBAL_PM_RXDLOZ_WAIT_MASK \ + (0xFF << HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET) + +#endif /* _COMPHY_HPIPE_H_ */ + diff --git a/drivers/phy/marvell/comphy_mux.c b/drivers/phy/marvell/comphy_mux.c new file mode 100644 index 0000000..1dc7426 --- /dev/null +++ b/drivers/phy/marvell/comphy_mux.c @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2015-2016 Marvell International Ltd. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include + +#include "comphy.h" +#include "comphy_hpipe.h" + +/* + * comphy_mux_check_config() + * description: this function passes over the COMPHY lanes and check if the type + * is valid for specific lane. If the type is not valid, + * the function update the struct and set the type of the lane as + * PHY_TYPE_UNCONNECTED + */ +static void comphy_mux_check_config(struct comphy_mux_data *mux_data, + struct comphy_map *comphy_map_data, int comphy_max_lanes) +{ + struct comphy_mux_options *mux_opt; + int lane, opt, valid; + + debug_enter(); + + for (lane = 0; lane < comphy_max_lanes; + lane++, comphy_map_data++, mux_data++) { + mux_opt = mux_data->mux_values; + for (opt = 0, valid = 0; opt < mux_data->max_lane_values; + opt++, mux_opt++) { + if (mux_opt->type == comphy_map_data->type) { + valid = 1; + break; + } + } + if (valid == 0) { + debug("lane number %d, had invalid type %d\n", + lane, comphy_map_data->type); + debug("set lane %d as type %d\n", lane, + PHY_TYPE_UNCONNECTED); + comphy_map_data->type = PHY_TYPE_UNCONNECTED; + } else { + debug("lane number %d, has type %d\n", + lane, comphy_map_data->type); + } + } + + debug_exit(); +} + +static u32 comphy_mux_get_mux_value(struct comphy_mux_data *mux_data, + u32 type, int lane) +{ + struct comphy_mux_options *mux_opt; + int opt; + u32 value = 0; + + debug_enter(); + + mux_opt = mux_data->mux_values; + for (opt = 0 ; opt < mux_data->max_lane_values; opt++, mux_opt++) { + if (mux_opt->type == type) { + value = mux_opt->mux_value; + break; + } + } + + debug_exit(); + + return value; +} + +static void comphy_mux_reg_write(struct comphy_mux_data *mux_data, + struct comphy_map *comphy_map_data, + int comphy_max_lanes, + void __iomem *selector_base, u32 bitcount) +{ + u32 lane, value, offset, mask; + + debug_enter(); + + for (lane = 0; lane < comphy_max_lanes; + lane++, comphy_map_data++, mux_data++) { + offset = lane * bitcount; + mask = (((1 << bitcount) - 1) << offset); + value = (comphy_mux_get_mux_value(mux_data, + comphy_map_data->type, + lane) << offset); + reg_set(selector_base, value, mask); + } + + debug_exit(); +} + +void comphy_mux_init(struct chip_serdes_phy_config *chip_cfg, + struct comphy_map *comphy_map_data, + void __iomem *selector_base) +{ + struct comphy_mux_data *mux_data; + u32 mux_bitcount; + u32 comphy_max_lanes; + + debug_enter(); + + comphy_max_lanes = chip_cfg->comphy_lanes_count; + mux_data = chip_cfg->mux_data; + mux_bitcount = chip_cfg->comphy_mux_bitcount; + + /* check if the configuration is valid */ + comphy_mux_check_config(mux_data, comphy_map_data, comphy_max_lanes); + /* Init COMPHY selectors */ + comphy_mux_reg_write(mux_data, comphy_map_data, comphy_max_lanes, + selector_base, mux_bitcount); + + debug_exit(); +} -- cgit v1.1 From c0132f60059d4a6809341d54f2fe744db8790421 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Tue, 30 Aug 2016 16:48:20 +0200 Subject: drivers/phy: Add Marvell SerDes / PHY drivers used on Armada 7K/8K This version is based on the Marvell U-Boot version with this patch applied as latest patch: Git ID 7f408573: "fix: comphy: cp110: add comphy initialization for usb device mode" from 2016-07-05. Signed-off-by: Stefan Roese Cc: Nadav Haklai Cc: Neta Zur Hershkovits Cc: Kostya Porotchkin Cc: Omri Itach Cc: Igal Liberman Cc: Haim Boot Cc: Hanna Hawa --- drivers/phy/marvell/Makefile | 1 + drivers/phy/marvell/comphy.h | 18 +- drivers/phy/marvell/comphy_core.c | 3 + drivers/phy/marvell/comphy_cp110.c | 1726 ++++++++++++++++++++++++++++++++++++ drivers/phy/marvell/comphy_hpipe.h | 38 + drivers/phy/marvell/sata.h | 30 + drivers/phy/marvell/utmi_phy.h | 90 ++ 7 files changed, 1904 insertions(+), 2 deletions(-) create mode 100644 drivers/phy/marvell/comphy_cp110.c create mode 100644 drivers/phy/marvell/sata.h create mode 100644 drivers/phy/marvell/utmi_phy.h (limited to 'drivers') diff --git a/drivers/phy/marvell/Makefile b/drivers/phy/marvell/Makefile index 91df554..f181505 100644 --- a/drivers/phy/marvell/Makefile +++ b/drivers/phy/marvell/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_MVEBU_COMPHY_SUPPORT) += comphy_core.o obj-$(CONFIG_MVEBU_COMPHY_SUPPORT) += comphy_mux.o obj-$(CONFIG_ARMADA_3700) += comphy_a3700.o +obj-$(CONFIG_ARMADA_8K) += comphy_cp110.o diff --git a/drivers/phy/marvell/comphy.h b/drivers/phy/marvell/comphy.h index 5c50e9c..df5b7d5 100644 --- a/drivers/phy/marvell/comphy.h +++ b/drivers/phy/marvell/comphy.h @@ -60,6 +60,9 @@ #define COMMON_PHY_SD_CTRL1_RXAUI0_MASK \ (0x1 << COMMON_PHY_SD_CTRL1_RXAUI0_OFFSET) +/* ToDo: Get this address via DT */ +#define MVEBU_CP0_REGS_BASE 0xF2000000UL + #define DFX_DEV_GEN_CTRL12 (MVEBU_CP0_REGS_BASE + 0x400280) #define DFX_DEV_GEN_PCIE_CLK_SRC_OFFSET 7 #define DFX_DEV_GEN_PCIE_CLK_SRC_MASK \ @@ -117,10 +120,21 @@ static inline int comphy_a3700_init(struct chip_serdes_phy_config *ptr_chip_cfg, return -1; } #endif -int comphy_ap806_init(struct chip_serdes_phy_config *ptr_chip_cfg, - struct comphy_map *serdes_map); + +#ifdef CONFIG_ARMADA_8K int comphy_cp110_init(struct chip_serdes_phy_config *ptr_chip_cfg, struct comphy_map *serdes_map); +#else +static inline int comphy_cp110_init(struct chip_serdes_phy_config *ptr_chip_cfg, + struct comphy_map *serdes_map) +{ + /* + * This function should never be called in this configuration, so + * lets return an error here. + */ + return -1; +} +#endif void comphy_dedicated_phys_init(void); diff --git a/drivers/phy/marvell/comphy_core.c b/drivers/phy/marvell/comphy_core.c index 67eb139..344df3b 100644 --- a/drivers/phy/marvell/comphy_core.c +++ b/drivers/phy/marvell/comphy_core.c @@ -139,6 +139,9 @@ static int comphy_probe(struct udevice *dev) if (of_device_is_compatible(dev, "marvell,comphy-armada-3700")) chip_cfg->ptr_comphy_chip_init = comphy_a3700_init; + if (of_device_is_compatible(dev, "marvell,comphy-cp110")) + chip_cfg->ptr_comphy_chip_init = comphy_cp110_init; + /* * Bail out if no chip_init function is defined, e.g. no * compatible node is found diff --git a/drivers/phy/marvell/comphy_cp110.c b/drivers/phy/marvell/comphy_cp110.c new file mode 100644 index 0000000..25c067d --- /dev/null +++ b/drivers/phy/marvell/comphy_cp110.c @@ -0,0 +1,1726 @@ +/* + * Copyright (C) 2015-2016 Marvell International Ltd. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +#include "comphy.h" +#include "comphy_hpipe.h" +#include "sata.h" +#include "utmi_phy.h" + +DECLARE_GLOBAL_DATA_PTR; + +#define SD_ADDR(base, lane) (base + 0x1000 * lane) +#define HPIPE_ADDR(base, lane) (SD_ADDR(base, lane) + 0x800) +#define COMPHY_ADDR(base, lane) (base + 0x28 * lane) + +struct utmi_phy_data { + void __iomem *utmi_base_addr; + void __iomem *usb_cfg_addr; + void __iomem *utmi_cfg_addr; + u32 utmi_phy_port; +}; + +/* + * For CP-110 we have 2 Selector registers "PHY Selectors", + * and "PIPE Selectors". + * PIPE selector include USB and PCIe options. + * PHY selector include the Ethernet and SATA options, every Ethernet + * option has different options, for example: serdes lane2 had option + * Eth_port_0 that include (SGMII0, XAUI0, RXAUI0, KR) + */ +struct comphy_mux_data cp110_comphy_phy_mux_data[] = { + {4, {{PHY_TYPE_UNCONNECTED, 0x0}, {PHY_TYPE_SGMII2, 0x1}, /* Lane 0 */ + {PHY_TYPE_XAUI2, 0x1}, {PHY_TYPE_SATA1, 0x4} } }, + {4, {{PHY_TYPE_UNCONNECTED, 0x0}, {PHY_TYPE_SGMII3, 0x1}, /* Lane 1 */ + {PHY_TYPE_XAUI3, 0x1}, {PHY_TYPE_SATA0, 0x4} } }, + {6, {{PHY_TYPE_UNCONNECTED, 0x0}, {PHY_TYPE_SGMII0, 0x1}, /* Lane 2 */ + {PHY_TYPE_XAUI0, 0x1}, {PHY_TYPE_RXAUI0, 0x1}, + {PHY_TYPE_KR, 0x1}, {PHY_TYPE_SATA0, 0x4} } }, + {8, {{PHY_TYPE_UNCONNECTED, 0x0}, {PHY_TYPE_SGMII0, 0x1}, /* Lane 3 */ + {PHY_TYPE_XAUI0, 0x1}, {PHY_TYPE_RXAUI0, 0x1}, + {PHY_TYPE_KR, 0x1}, {PHY_TYPE_XAUI1, 0x1}, + {PHY_TYPE_RXAUI1, 0x1}, {PHY_TYPE_SATA1, 0x4} } }, + {7, {{PHY_TYPE_UNCONNECTED, 0x0}, {PHY_TYPE_SGMII0, 0x2}, /* Lane 4 */ + {PHY_TYPE_XAUI0, 0x1}, {PHY_TYPE_RXAUI0, 0x1}, {PHY_TYPE_KR, 0x1}, + {PHY_TYPE_SGMII2, 0x1}, {PHY_TYPE_XAUI2, 0x1} } }, + {6, {{PHY_TYPE_UNCONNECTED, 0x0}, {PHY_TYPE_XAUI1, 0x1}, /* Lane 5 */ + {PHY_TYPE_RXAUI1, 0x1}, {PHY_TYPE_SGMII3, 0x1}, + {PHY_TYPE_XAUI3, 0x1}, {PHY_TYPE_SATA1, 0x4} } }, +}; + +struct comphy_mux_data cp110_comphy_pipe_mux_data[] = { + {2, {{PHY_TYPE_UNCONNECTED, 0x0}, {PHY_TYPE_PEX0, 0x4} } }, /* Lane 0 */ + {4, {{PHY_TYPE_UNCONNECTED, 0x0}, /* Lane 1 */ + {PHY_TYPE_USB3_HOST0, 0x1}, {PHY_TYPE_USB3_DEVICE, 0x2}, + {PHY_TYPE_PEX0, 0x4} } }, + {3, {{PHY_TYPE_UNCONNECTED, 0x0}, /* Lane 2 */ + {PHY_TYPE_USB3_HOST0, 0x1}, {PHY_TYPE_PEX0, 0x4} } }, + {3, {{PHY_TYPE_UNCONNECTED, 0x0}, /* Lane 3 */ + {PHY_TYPE_USB3_HOST1, 0x1}, {PHY_TYPE_PEX0, 0x4} } }, + {4, {{PHY_TYPE_UNCONNECTED, 0x0}, /* Lane 4 */ + {PHY_TYPE_USB3_HOST1, 0x1}, + {PHY_TYPE_USB3_DEVICE, 0x2}, {PHY_TYPE_PEX1, 0x4} } }, + {2, {{PHY_TYPE_UNCONNECTED, 0x0}, {PHY_TYPE_PEX2, 0x4} } }, /* Lane 5 */ +}; + +static u32 polling_with_timeout(void __iomem *addr, u32 val, + u32 mask, unsigned long usec_timout) +{ + u32 data; + + do { + udelay(1); + data = readl(addr) & mask; + } while (data != val && --usec_timout > 0); + + if (usec_timout == 0) + return data; + + return 0; +} + +static int comphy_pcie_power_up(u32 lane, u32 pcie_width, + bool clk_src, void __iomem *hpipe_base, + void __iomem *comphy_base) +{ + u32 mask, data, ret = 1; + void __iomem *hpipe_addr = HPIPE_ADDR(hpipe_base, lane); + void __iomem *comphy_addr = COMPHY_ADDR(comphy_base, lane); + void __iomem *addr; + u32 pcie_clk = 0; /* set input by default */ + + debug_enter(); + + /* + * ToDo: + * Add SAR (Sample-At-Reset) configuration for the PCIe clock + * direction. SAR code is currently not ported from Marvell + * U-Boot to mainline version. + * + * SerDes Lane 4/5 got the PCIe ref-clock #1, + * and SerDes Lane 0 got PCIe ref-clock #0 + */ + debug("PCIe clock = %x\n", pcie_clk); + debug("PCIe width = %d\n", pcie_width); + + /* enable PCIe by4 and by2 */ + if (lane == 0) { + if (pcie_width == 4) { + reg_set(comphy_base + COMMON_PHY_SD_CTRL1, + 0x1 << COMMON_PHY_SD_CTRL1_PCIE_X4_EN_OFFSET, + COMMON_PHY_SD_CTRL1_PCIE_X4_EN_MASK); + } else if (pcie_width == 2) { + reg_set(comphy_base + COMMON_PHY_SD_CTRL1, + 0x1 << COMMON_PHY_SD_CTRL1_PCIE_X2_EN_OFFSET, + COMMON_PHY_SD_CTRL1_PCIE_X2_EN_MASK); + } + } + + /* + * If PCIe clock is output and clock source from SerDes lane 5, + * we need to configure the clock-source MUX. + * By default, the clock source is from lane 4 + */ + if (pcie_clk && clk_src && (lane == 5)) { + reg_set((void __iomem *)DFX_DEV_GEN_CTRL12, + 0x3 << DFX_DEV_GEN_PCIE_CLK_SRC_OFFSET, + DFX_DEV_GEN_PCIE_CLK_SRC_MASK); + } + + debug("stage: RFU configurations - hard reset comphy\n"); + /* RFU configurations - hard reset comphy */ + mask = COMMON_PHY_CFG1_PWR_UP_MASK; + data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET; + mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK; + data |= 0x1 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET; + mask |= COMMON_PHY_CFG1_PWR_ON_RESET_MASK; + data |= 0x0 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET; + mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK; + data |= 0x0 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET; + mask |= COMMON_PHY_PHY_MODE_MASK; + data |= 0x0 << COMMON_PHY_PHY_MODE_OFFSET; + reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask); + + /* release from hard reset */ + mask = COMMON_PHY_CFG1_PWR_ON_RESET_MASK; + data = 0x1 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET; + mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK; + data |= 0x1 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET; + reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask); + + /* Wait 1ms - until band gap and ref clock ready */ + mdelay(1); + /* Start comphy Configuration */ + debug("stage: Comphy configuration\n"); + /* Set PIPE soft reset */ + mask = HPIPE_RST_CLK_CTRL_PIPE_RST_MASK; + data = 0x1 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET; + /* Set PHY datapath width mode for V0 */ + mask |= HPIPE_RST_CLK_CTRL_FIXED_PCLK_MASK; + data |= 0x1 << HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET; + /* Set Data bus width USB mode for V0 */ + mask |= HPIPE_RST_CLK_CTRL_PIPE_WIDTH_MASK; + data |= 0x0 << HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET; + /* Set CORE_CLK output frequency for 250Mhz */ + mask |= HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_MASK; + data |= 0x0 << HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET; + reg_set(hpipe_addr + HPIPE_RST_CLK_CTRL_REG, data, mask); + /* Set PLL ready delay for 0x2 */ + data = 0x2 << HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET; + mask = HPIPE_CLK_SRC_LO_PLL_RDY_DL_MASK; + if (pcie_width != 1) { + data |= 0x1 << HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_OFFSET; + mask |= HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_MASK; + data |= 0x1 << HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_OFFSET; + mask |= HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_MASK; + } + reg_set(hpipe_addr + HPIPE_CLK_SRC_LO_REG, data, mask); + + /* Set PIPE mode interface to PCIe3 - 0x1 & set lane order */ + data = 0x1 << HPIPE_CLK_SRC_HI_MODE_PIPE_OFFSET; + mask = HPIPE_CLK_SRC_HI_MODE_PIPE_MASK; + if (pcie_width != 1) { + mask |= HPIPE_CLK_SRC_HI_LANE_STRT_MASK; + mask |= HPIPE_CLK_SRC_HI_LANE_MASTER_MASK; + mask |= HPIPE_CLK_SRC_HI_LANE_BREAK_MASK; + if (lane == 0) { + data |= 0x1 << HPIPE_CLK_SRC_HI_LANE_STRT_OFFSET; + data |= 0x1 << HPIPE_CLK_SRC_HI_LANE_MASTER_OFFSET; + } else if (lane == (pcie_width - 1)) { + data |= 0x1 << HPIPE_CLK_SRC_HI_LANE_BREAK_OFFSET; + } + } + reg_set(hpipe_addr + HPIPE_CLK_SRC_HI_REG, data, mask); + /* Config update polarity equalization */ + reg_set(hpipe_addr + HPIPE_LANE_EQ_CFG1_REG, + 0x1 << HPIPE_CFG_UPDATE_POLARITY_OFFSET, + HPIPE_CFG_UPDATE_POLARITY_MASK); + /* Set PIPE version 4 to mode enable */ + reg_set(hpipe_addr + HPIPE_DFE_CTRL_28_REG, + 0x1 << HPIPE_DFE_CTRL_28_PIPE4_OFFSET, + HPIPE_DFE_CTRL_28_PIPE4_MASK); + /* TODO: check if pcie clock is output/input - for bringup use input*/ + /* Enable PIN clock 100M_125M */ + mask = 0; + data = 0; + /* Only if clock is output, configure the clock-source mux */ + if (pcie_clk) { + mask |= HPIPE_MISC_CLK100M_125M_MASK; + data |= 0x1 << HPIPE_MISC_CLK100M_125M_OFFSET; + } + /* + * Set PIN_TXDCLK_2X Clock Frequency Selection for outputs 500MHz + * clock + */ + mask |= HPIPE_MISC_TXDCLK_2X_MASK; + data |= 0x0 << HPIPE_MISC_TXDCLK_2X_OFFSET; + /* Enable 500MHz Clock */ + mask |= HPIPE_MISC_CLK500_EN_MASK; + data |= 0x1 << HPIPE_MISC_CLK500_EN_OFFSET; + if (pcie_clk) { /* output */ + /* Set reference clock comes from group 1 */ + mask |= HPIPE_MISC_REFCLK_SEL_MASK; + data |= 0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET; + } else { + /* Set reference clock comes from group 2 */ + mask |= HPIPE_MISC_REFCLK_SEL_MASK; + data |= 0x1 << HPIPE_MISC_REFCLK_SEL_OFFSET; + } + reg_set(hpipe_addr + HPIPE_MISC_REG, data, mask); + if (pcie_clk) { /* output */ + /* Set reference frequcency select - 0x2 for 25MHz*/ + mask = HPIPE_PWR_PLL_REF_FREQ_MASK; + data = 0x2 << HPIPE_PWR_PLL_REF_FREQ_OFFSET; + } else { + /* Set reference frequcency select - 0x0 for 100MHz*/ + mask = HPIPE_PWR_PLL_REF_FREQ_MASK; + data = 0x0 << HPIPE_PWR_PLL_REF_FREQ_OFFSET; + } + /* Set PHY mode to PCIe */ + mask |= HPIPE_PWR_PLL_PHY_MODE_MASK; + data |= 0x3 << HPIPE_PWR_PLL_PHY_MODE_OFFSET; + reg_set(hpipe_addr + HPIPE_PWR_PLL_REG, data, mask); + + /* ref clock alignment */ + if (pcie_width != 1) { + mask = HPIPE_LANE_ALIGN_OFF_MASK; + data = 0x0 << HPIPE_LANE_ALIGN_OFF_OFFSET; + reg_set(hpipe_addr + HPIPE_LANE_ALIGN_REG, data, mask); + } + + /* + * Set the amount of time spent in the LoZ state - set for 0x7 only if + * the PCIe clock is output + */ + if (pcie_clk) { + reg_set(hpipe_addr + HPIPE_GLOBAL_PM_CTRL, + 0x7 << HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET, + HPIPE_GLOBAL_PM_RXDLOZ_WAIT_MASK); + } + + /* Set Maximal PHY Generation Setting(8Gbps) */ + mask = HPIPE_INTERFACE_GEN_MAX_MASK; + data = 0x2 << HPIPE_INTERFACE_GEN_MAX_OFFSET; + /* Set Link Train Mode (Tx training control pins are used) */ + mask |= HPIPE_INTERFACE_LINK_TRAIN_MASK; + data |= 0x1 << HPIPE_INTERFACE_LINK_TRAIN_OFFSET; + reg_set(hpipe_addr + HPIPE_INTERFACE_REG, data, mask); + + /* Set Idle_sync enable */ + mask = HPIPE_PCIE_IDLE_SYNC_MASK; + data = 0x1 << HPIPE_PCIE_IDLE_SYNC_OFFSET; + /* Select bits for PCIE Gen3(32bit) */ + mask |= HPIPE_PCIE_SEL_BITS_MASK; + data |= 0x2 << HPIPE_PCIE_SEL_BITS_OFFSET; + reg_set(hpipe_addr + HPIPE_PCIE_REG0, data, mask); + + /* Enable Tx_adapt_g1 */ + mask = HPIPE_TX_TRAIN_CTRL_G1_MASK; + data = 0x1 << HPIPE_TX_TRAIN_CTRL_G1_OFFSET; + /* Enable Tx_adapt_gn1 */ + mask |= HPIPE_TX_TRAIN_CTRL_GN1_MASK; + data |= 0x1 << HPIPE_TX_TRAIN_CTRL_GN1_OFFSET; + /* Disable Tx_adapt_g0 */ + mask |= HPIPE_TX_TRAIN_CTRL_G0_MASK; + data |= 0x0 << HPIPE_TX_TRAIN_CTRL_G0_OFFSET; + reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_REG, data, mask); + + /* Set reg_tx_train_chk_init */ + mask = HPIPE_TX_TRAIN_CHK_INIT_MASK; + data = 0x0 << HPIPE_TX_TRAIN_CHK_INIT_OFFSET; + /* Enable TX_COE_FM_PIN_PCIE3_EN */ + mask |= HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_MASK; + data |= 0x1 << HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_OFFSET; + reg_set(hpipe_addr + HPIPE_TX_TRAIN_REG, data, mask); + + debug("stage: TRx training parameters\n"); + /* Set Preset sweep configurations */ + mask = HPIPE_TX_TX_STATUS_CHECK_MODE_MASK; + data = 0x1 << HPIPE_TX_STATUS_CHECK_MODE_OFFSET; + + mask |= HPIPE_TX_NUM_OF_PRESET_MASK; + data |= 0x7 << HPIPE_TX_NUM_OF_PRESET_OFFSET; + + mask |= HPIPE_TX_SWEEP_PRESET_EN_MASK; + data |= 0x1 << HPIPE_TX_SWEEP_PRESET_EN_OFFSET; + reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_11_REG, data, mask); + + /* Tx train start configuration */ + mask = HPIPE_TX_TRAIN_START_SQ_EN_MASK; + data = 0x1 << HPIPE_TX_TRAIN_START_SQ_EN_OFFSET; + + mask |= HPIPE_TX_TRAIN_START_FRM_DET_EN_MASK; + data |= 0x0 << HPIPE_TX_TRAIN_START_FRM_DET_EN_OFFSET; + + mask |= HPIPE_TX_TRAIN_START_FRM_LOCK_EN_MASK; + data |= 0x0 << HPIPE_TX_TRAIN_START_FRM_LOCK_EN_OFFSET; + + mask |= HPIPE_TX_TRAIN_WAIT_TIME_EN_MASK; + data |= 0x1 << HPIPE_TX_TRAIN_WAIT_TIME_EN_OFFSET; + reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_5_REG, data, mask); + + /* Enable Tx train P2P */ + mask = HPIPE_TX_TRAIN_P2P_HOLD_MASK; + data = 0x1 << HPIPE_TX_TRAIN_P2P_HOLD_OFFSET; + reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_0_REG, data, mask); + + /* Configure Tx train timeout */ + mask = HPIPE_TRX_TRAIN_TIMER_MASK; + data = 0x17 << HPIPE_TRX_TRAIN_TIMER_OFFSET; + reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_4_REG, data, mask); + + /* Disable G0/G1/GN1 adaptation */ + mask = HPIPE_TX_TRAIN_CTRL_G1_MASK | HPIPE_TX_TRAIN_CTRL_GN1_MASK + | HPIPE_TX_TRAIN_CTRL_G0_OFFSET; + data = 0; + reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_REG, data, mask); + + /* Disable DTL frequency loop */ + mask = HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK; + data = 0x0 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET; + reg_set(hpipe_addr + HPIPE_PWR_CTR_DTL_REG, data, mask); + + /* Configure G3 DFE */ + mask = HPIPE_G3_DFE_RES_MASK; + data = 0x3 << HPIPE_G3_DFE_RES_OFFSET; + reg_set(hpipe_addr + HPIPE_G3_SETTING_4_REG, data, mask); + + /* Force DFE resolution (use GEN table value) */ + mask = HPIPE_DFE_RES_FORCE_MASK; + data = 0x1 << HPIPE_DFE_RES_FORCE_OFFSET; + reg_set(hpipe_addr + HPIPE_DFE_REG0, data, mask); + + /* Configure initial and final coefficient value for receiver */ + mask = HPIPE_G3_RX_SELMUPI_MASK; + data = 0x1 << HPIPE_G3_RX_SELMUPI_OFFSET; + + mask |= HPIPE_G3_RX_SELMUPF_MASK; + data |= 0x1 << HPIPE_G3_RX_SELMUPF_OFFSET; + + mask |= HPIPE_G3_SETTING_BIT_MASK; + data |= 0x0 << HPIPE_G3_SETTING_BIT_OFFSET; + reg_set(hpipe_addr + HPIPE_G3_SETTINGS_1_REG, data, mask); + + /* Trigger sampler enable pulse */ + mask = HPIPE_SMAPLER_MASK; + data = 0x1 << HPIPE_SMAPLER_OFFSET; + reg_set(hpipe_addr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, data, mask); + udelay(5); + reg_set(hpipe_addr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, 0, mask); + + /* FFE resistor tuning for different bandwidth */ + mask = HPIPE_G3_FFE_DEG_RES_LEVEL_MASK; + data = 0x1 << HPIPE_G3_FFE_DEG_RES_LEVEL_OFFSET; + + mask |= HPIPE_G3_FFE_LOAD_RES_LEVEL_MASK; + data |= 0x1 << HPIPE_G3_FFE_LOAD_RES_LEVEL_OFFSET; + reg_set(hpipe_addr + HPIPE_G3_SETTING_3_REG, data, mask); + + /* Set phy in root complex mode */ + mask = HPIPE_CFG_PHY_RC_EP_MASK; + data = 0x1 << HPIPE_CFG_PHY_RC_EP_OFFSET; + reg_set(hpipe_addr + HPIPE_LANE_EQU_CONFIG_0_REG, data, mask); + + debug("stage: Comphy power up\n"); + + /* + * For PCIe by4 or by2 - release from reset only after finish to + * configure all lanes + */ + if ((pcie_width == 1) || (lane == (pcie_width - 1))) { + u32 i, start_lane, end_lane; + + if (pcie_width != 1) { + /* allows writing to all lanes in one write */ + reg_set(comphy_base + COMMON_PHY_SD_CTRL1, + 0x0 << + COMMON_PHY_SD_CTRL1_COMPHY_0_4_PORT_OFFSET, + COMMON_PHY_SD_CTRL1_COMPHY_0_4_PORT_MASK); + start_lane = 0; + end_lane = pcie_width; + + /* + * Release from PIPE soft reset + * for PCIe by4 or by2 - release from soft reset + * all lanes - can't use read modify write + */ + reg_set(HPIPE_ADDR(hpipe_base, 0) + + HPIPE_RST_CLK_CTRL_REG, 0x24, 0xffffffff); + } else { + start_lane = lane; + end_lane = lane + 1; + + /* + * Release from PIPE soft reset + * for PCIe by4 or by2 - release from soft reset + * all lanes + */ + reg_set(hpipe_addr + HPIPE_RST_CLK_CTRL_REG, + 0x0 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET, + HPIPE_RST_CLK_CTRL_PIPE_RST_MASK); + } + + + if (pcie_width != 1) { + /* disable writing to all lanes with one write */ + reg_set(comphy_base + COMMON_PHY_SD_CTRL1, + 0x3210 << + COMMON_PHY_SD_CTRL1_COMPHY_0_4_PORT_OFFSET, + COMMON_PHY_SD_CTRL1_COMPHY_0_4_PORT_MASK); + } + + debug("stage: Check PLL\n"); + /* Read lane status */ + for (i = start_lane; i < end_lane; i++) { + addr = HPIPE_ADDR(hpipe_base, i) + + HPIPE_LANE_STATUS1_REG; + data = HPIPE_LANE_STATUS1_PCLK_EN_MASK; + mask = data; + data = polling_with_timeout(addr, data, mask, 15000); + if (data != 0) { + debug("Read from reg = %p - value = 0x%x\n", + hpipe_addr + HPIPE_LANE_STATUS1_REG, + data); + error("HPIPE_LANE_STATUS1_PCLK_EN_MASK is 0\n"); + ret = 0; + } + } + } + + debug_exit(); + return ret; +} + +static int comphy_usb3_power_up(u32 lane, void __iomem *hpipe_base, + void __iomem *comphy_base) +{ + u32 mask, data, ret = 1; + void __iomem *hpipe_addr = HPIPE_ADDR(hpipe_base, lane); + void __iomem *comphy_addr = COMPHY_ADDR(comphy_base, lane); + void __iomem *addr; + + debug_enter(); + debug("stage: RFU configurations - hard reset comphy\n"); + /* RFU configurations - hard reset comphy */ + mask = COMMON_PHY_CFG1_PWR_UP_MASK; + data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET; + mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK; + data |= 0x1 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET; + mask |= COMMON_PHY_CFG1_PWR_ON_RESET_MASK; + data |= 0x0 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET; + mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK; + data |= 0x0 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET; + mask |= COMMON_PHY_PHY_MODE_MASK; + data |= 0x1 << COMMON_PHY_PHY_MODE_OFFSET; + reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask); + + /* release from hard reset */ + mask = COMMON_PHY_CFG1_PWR_ON_RESET_MASK; + data = 0x1 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET; + mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK; + data |= 0x1 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET; + reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask); + + /* Wait 1ms - until band gap and ref clock ready */ + mdelay(1); + + /* Start comphy Configuration */ + debug("stage: Comphy configuration\n"); + /* Set PIPE soft reset */ + mask = HPIPE_RST_CLK_CTRL_PIPE_RST_MASK; + data = 0x1 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET; + /* Set PHY datapath width mode for V0 */ + mask |= HPIPE_RST_CLK_CTRL_FIXED_PCLK_MASK; + data |= 0x0 << HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET; + /* Set Data bus width USB mode for V0 */ + mask |= HPIPE_RST_CLK_CTRL_PIPE_WIDTH_MASK; + data |= 0x0 << HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET; + /* Set CORE_CLK output frequency for 250Mhz */ + mask |= HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_MASK; + data |= 0x0 << HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET; + reg_set(hpipe_addr + HPIPE_RST_CLK_CTRL_REG, data, mask); + /* Set PLL ready delay for 0x2 */ + reg_set(hpipe_addr + HPIPE_CLK_SRC_LO_REG, + 0x2 << HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET, + HPIPE_CLK_SRC_LO_PLL_RDY_DL_MASK); + /* Set reference clock to come from group 1 - 25Mhz */ + reg_set(hpipe_addr + HPIPE_MISC_REG, + 0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET, + HPIPE_MISC_REFCLK_SEL_MASK); + /* Set reference frequcency select - 0x2 */ + mask = HPIPE_PWR_PLL_REF_FREQ_MASK; + data = 0x2 << HPIPE_PWR_PLL_REF_FREQ_OFFSET; + /* Set PHY mode to USB - 0x5 */ + mask |= HPIPE_PWR_PLL_PHY_MODE_MASK; + data |= 0x5 << HPIPE_PWR_PLL_PHY_MODE_OFFSET; + reg_set(hpipe_addr + HPIPE_PWR_PLL_REG, data, mask); + /* Set the amount of time spent in the LoZ state - set for 0x7 */ + reg_set(hpipe_addr + HPIPE_GLOBAL_PM_CTRL, + 0x7 << HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET, + HPIPE_GLOBAL_PM_RXDLOZ_WAIT_MASK); + /* Set max PHY generation setting - 5Gbps */ + reg_set(hpipe_addr + HPIPE_INTERFACE_REG, + 0x1 << HPIPE_INTERFACE_GEN_MAX_OFFSET, + HPIPE_INTERFACE_GEN_MAX_MASK); + /* Set select data width 20Bit (SEL_BITS[2:0]) */ + reg_set(hpipe_addr + HPIPE_LOOPBACK_REG, + 0x1 << HPIPE_LOOPBACK_SEL_OFFSET, + HPIPE_LOOPBACK_SEL_MASK); + /* select de-emphasize 3.5db */ + reg_set(hpipe_addr + HPIPE_LANE_CONFIG0_REG, + 0x1 << HPIPE_LANE_CONFIG0_TXDEEMPH0_OFFSET, + HPIPE_LANE_CONFIG0_TXDEEMPH0_MASK); + /* override tx margining from the MAC */ + reg_set(hpipe_addr + HPIPE_TST_MODE_CTRL_REG, + 0x1 << HPIPE_TST_MODE_CTRL_MODE_MARGIN_OFFSET, + HPIPE_TST_MODE_CTRL_MODE_MARGIN_MASK); + + /* Start analog paramters from ETP(HW) */ + debug("stage: Analog paramters from ETP(HW)\n"); + /* Set Pin DFE_PAT_DIS -> Bit[1]: PIN_DFE_PAT_DIS = 0x0 */ + mask = HPIPE_LANE_CFG4_DFE_CTRL_MASK; + data = 0x1 << HPIPE_LANE_CFG4_DFE_CTRL_OFFSET; + /* Set Override PHY DFE control pins for 0x1 */ + mask |= HPIPE_LANE_CFG4_DFE_OVER_MASK; + data |= 0x1 << HPIPE_LANE_CFG4_DFE_OVER_OFFSET; + /* Set Spread Spectrum Clock Enable fot 0x1 */ + mask |= HPIPE_LANE_CFG4_SSC_CTRL_MASK; + data |= 0x1 << HPIPE_LANE_CFG4_SSC_CTRL_OFFSET; + reg_set(hpipe_addr + HPIPE_LANE_CFG4_REG, data, mask); + /* End of analog parameters */ + + debug("stage: Comphy power up\n"); + /* Release from PIPE soft reset */ + reg_set(hpipe_addr + HPIPE_RST_CLK_CTRL_REG, + 0x0 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET, + HPIPE_RST_CLK_CTRL_PIPE_RST_MASK); + + /* wait 15ms - for comphy calibration done */ + debug("stage: Check PLL\n"); + /* Read lane status */ + addr = hpipe_addr + HPIPE_LANE_STATUS1_REG; + data = HPIPE_LANE_STATUS1_PCLK_EN_MASK; + mask = data; + data = polling_with_timeout(addr, data, mask, 15000); + if (data != 0) { + debug("Read from reg = %p - value = 0x%x\n", + hpipe_addr + HPIPE_LANE_STATUS1_REG, data); + error("HPIPE_LANE_STATUS1_PCLK_EN_MASK is 0\n"); + ret = 0; + } + + debug_exit(); + return ret; +} + +static int comphy_sata_power_up(u32 lane, void __iomem *hpipe_base, + void __iomem *comphy_base, int comphy_index) +{ + u32 mask, data, i, ret = 1; + void __iomem *hpipe_addr = HPIPE_ADDR(hpipe_base, lane); + void __iomem *sd_ip_addr = SD_ADDR(hpipe_base, lane); + void __iomem *comphy_addr = COMPHY_ADDR(comphy_base, lane); + void __iomem *addr; + void __iomem *sata_base = NULL; + int sata_node = -1; /* Set to -1 in order to read the first sata node */ + + debug_enter(); + + /* + * Assumption - each CP has only one SATA controller + * Calling fdt_node_offset_by_compatible first time (with sata_node = -1 + * will return the first node always. + * In order to parse each CPs SATA node, fdt_node_offset_by_compatible + * must be called again (according to the CP id) + */ + for (i = 0; i < (comphy_index + 1); i++) + sata_node = fdt_node_offset_by_compatible( + gd->fdt_blob, sata_node, "marvell,armada-8k-ahci"); + + if (sata_node == 0) { + error("SATA node not found in FDT\n"); + return 0; + } + + sata_base = (void __iomem *)fdtdec_get_addr_size_auto_noparent( + gd->fdt_blob, sata_node, "reg", 0, NULL, true); + if (sata_base == NULL) { + error("SATA address not found in FDT\n"); + return 0; + } + + debug("SATA address found in FDT %p\n", sata_base); + + debug("stage: MAC configuration - power down comphy\n"); + /* + * MAC configuration powe down comphy use indirect address for + * vendor spesific SATA control register + */ + reg_set(sata_base + SATA3_VENDOR_ADDRESS, + SATA_CONTROL_REG << SATA3_VENDOR_ADDR_OFSSET, + SATA3_VENDOR_ADDR_MASK); + /* SATA 0 power down */ + mask = SATA3_CTRL_SATA0_PD_MASK; + data = 0x1 << SATA3_CTRL_SATA0_PD_OFFSET; + /* SATA 1 power down */ + mask |= SATA3_CTRL_SATA1_PD_MASK; + data |= 0x1 << SATA3_CTRL_SATA1_PD_OFFSET; + /* SATA SSU disable */ + mask |= SATA3_CTRL_SATA1_ENABLE_MASK; + data |= 0x0 << SATA3_CTRL_SATA1_ENABLE_OFFSET; + /* SATA port 1 disable */ + mask |= SATA3_CTRL_SATA_SSU_MASK; + data |= 0x0 << SATA3_CTRL_SATA_SSU_OFFSET; + reg_set(sata_base + SATA3_VENDOR_DATA, data, mask); + + debug("stage: RFU configurations - hard reset comphy\n"); + /* RFU configurations - hard reset comphy */ + mask = COMMON_PHY_CFG1_PWR_UP_MASK; + data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET; + mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK; + data |= 0x0 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET; + mask |= COMMON_PHY_CFG1_PWR_ON_RESET_MASK; + data |= 0x0 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET; + mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK; + data |= 0x0 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET; + reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask); + + /* Set select data width 40Bit - SATA mode only */ + reg_set(comphy_addr + COMMON_PHY_CFG6_REG, + 0x1 << COMMON_PHY_CFG6_IF_40_SEL_OFFSET, + COMMON_PHY_CFG6_IF_40_SEL_MASK); + + /* release from hard reset in SD external */ + mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK; + data = 0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET; + mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK; + data |= 0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET; + reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask); + + /* Wait 1ms - until band gap and ref clock ready */ + mdelay(1); + + debug("stage: Comphy configuration\n"); + /* Start comphy Configuration */ + /* Set reference clock to comes from group 1 - choose 25Mhz */ + reg_set(hpipe_addr + HPIPE_MISC_REG, + 0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET, + HPIPE_MISC_REFCLK_SEL_MASK); + /* Reference frequency select set 1 (for SATA = 25Mhz) */ + mask = HPIPE_PWR_PLL_REF_FREQ_MASK; + data = 0x1 << HPIPE_PWR_PLL_REF_FREQ_OFFSET; + /* PHY mode select (set SATA = 0x0 */ + mask |= HPIPE_PWR_PLL_PHY_MODE_MASK; + data |= 0x0 << HPIPE_PWR_PLL_PHY_MODE_OFFSET; + reg_set(hpipe_addr + HPIPE_PWR_PLL_REG, data, mask); + /* Set max PHY generation setting - 6Gbps */ + reg_set(hpipe_addr + HPIPE_INTERFACE_REG, + 0x2 << HPIPE_INTERFACE_GEN_MAX_OFFSET, + HPIPE_INTERFACE_GEN_MAX_MASK); + /* Set select data width 40Bit (SEL_BITS[2:0]) */ + reg_set(hpipe_addr + HPIPE_LOOPBACK_REG, + 0x2 << HPIPE_LOOPBACK_SEL_OFFSET, HPIPE_LOOPBACK_SEL_MASK); + + debug("stage: Analog paramters from ETP(HW)\n"); + /* + * TODO: Set analog paramters from ETP(HW) - for now use the + * default datas + */ + + /* DFE reset sequence */ + reg_set(hpipe_addr + HPIPE_PWR_CTR_REG, + 0x1 << HPIPE_PWR_CTR_RST_DFE_OFFSET, + HPIPE_PWR_CTR_RST_DFE_MASK); + reg_set(hpipe_addr + HPIPE_PWR_CTR_REG, + 0x0 << HPIPE_PWR_CTR_RST_DFE_OFFSET, + HPIPE_PWR_CTR_RST_DFE_MASK); + /* SW reset for interupt logic */ + reg_set(hpipe_addr + HPIPE_PWR_CTR_REG, + 0x1 << HPIPE_PWR_CTR_SFT_RST_OFFSET, + HPIPE_PWR_CTR_SFT_RST_MASK); + reg_set(hpipe_addr + HPIPE_PWR_CTR_REG, + 0x0 << HPIPE_PWR_CTR_SFT_RST_OFFSET, + HPIPE_PWR_CTR_SFT_RST_MASK); + + debug("stage: Comphy power up\n"); + /* + * MAC configuration power up comphy - power up PLL/TX/RX + * use indirect address for vendor spesific SATA control register + */ + reg_set(sata_base + SATA3_VENDOR_ADDRESS, + SATA_CONTROL_REG << SATA3_VENDOR_ADDR_OFSSET, + SATA3_VENDOR_ADDR_MASK); + /* SATA 0 power up */ + mask = SATA3_CTRL_SATA0_PD_MASK; + data = 0x0 << SATA3_CTRL_SATA0_PD_OFFSET; + /* SATA 1 power up */ + mask |= SATA3_CTRL_SATA1_PD_MASK; + data |= 0x0 << SATA3_CTRL_SATA1_PD_OFFSET; + /* SATA SSU enable */ + mask |= SATA3_CTRL_SATA1_ENABLE_MASK; + data |= 0x1 << SATA3_CTRL_SATA1_ENABLE_OFFSET; + /* SATA port 1 enable */ + mask |= SATA3_CTRL_SATA_SSU_MASK; + data |= 0x1 << SATA3_CTRL_SATA_SSU_OFFSET; + reg_set(sata_base + SATA3_VENDOR_DATA, data, mask); + + /* MBUS request size and interface select register */ + reg_set(sata_base + SATA3_VENDOR_ADDRESS, + SATA_MBUS_SIZE_SELECT_REG << SATA3_VENDOR_ADDR_OFSSET, + SATA3_VENDOR_ADDR_MASK); + /* Mbus regret enable */ + reg_set(sata_base + SATA3_VENDOR_DATA, + 0x1 << SATA_MBUS_REGRET_EN_OFFSET, SATA_MBUS_REGRET_EN_MASK); + + debug("stage: Check PLL\n"); + + addr = sd_ip_addr + SD_EXTERNAL_STATUS0_REG; + data = SD_EXTERNAL_STATUS0_PLL_TX_MASK & + SD_EXTERNAL_STATUS0_PLL_RX_MASK; + mask = data; + data = polling_with_timeout(addr, data, mask, 15000); + if (data != 0) { + debug("Read from reg = %p - value = 0x%x\n", + hpipe_addr + HPIPE_LANE_STATUS1_REG, data); + error("SD_EXTERNAL_STATUS0_PLL_TX is %d, SD_EXTERNAL_STATUS0_PLL_RX is %d\n", + (data & SD_EXTERNAL_STATUS0_PLL_TX_MASK), + (data & SD_EXTERNAL_STATUS0_PLL_RX_MASK)); + ret = 0; + } + + debug_exit(); + return ret; +} + +static int comphy_sgmii_power_up(u32 lane, u32 sgmii_speed, + void __iomem *hpipe_base, + void __iomem *comphy_base) +{ + u32 mask, data, ret = 1; + void __iomem *hpipe_addr = HPIPE_ADDR(hpipe_base, lane); + void __iomem *sd_ip_addr = SD_ADDR(hpipe_base, lane); + void __iomem *comphy_addr = COMPHY_ADDR(comphy_base, lane); + void __iomem *addr; + + debug_enter(); + debug("stage: RFU configurations - hard reset comphy\n"); + /* RFU configurations - hard reset comphy */ + mask = COMMON_PHY_CFG1_PWR_UP_MASK; + data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET; + mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK; + data |= 0x0 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET; + reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask); + + /* Select Baud Rate of Comphy And PD_PLL/Tx/Rx */ + mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK; + data = 0x0 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET; + mask |= SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_MASK; + mask |= SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_MASK; + if (sgmii_speed == PHY_SPEED_1_25G) { + data |= 0x6 << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET; + data |= 0x6 << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET; + } else { + /* 3.125G */ + data |= 0x8 << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET; + data |= 0x8 << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET; + } + mask |= SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK; + data |= 0 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET; + mask |= SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK; + data |= 0 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET; + mask |= SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_MASK; + data |= 1 << SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_OFFSET; + reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG0_REG, data, mask); + + /* release from hard reset */ + mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK; + data = 0x0 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET; + mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK; + data |= 0x0 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET; + mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK; + data |= 0x0 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET; + reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask); + + /* release from hard reset */ + mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK; + data = 0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET; + mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK; + data |= 0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET; + reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask); + + + /* Wait 1ms - until band gap and ref clock ready */ + mdelay(1); + + /* Start comphy Configuration */ + debug("stage: Comphy configuration\n"); + /* set reference clock */ + mask = HPIPE_MISC_REFCLK_SEL_MASK; + data = 0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET; + reg_set(hpipe_addr + HPIPE_MISC_REG, data, mask); + /* Power and PLL Control */ + mask = HPIPE_PWR_PLL_REF_FREQ_MASK; + data = 0x1 << HPIPE_PWR_PLL_REF_FREQ_OFFSET; + mask |= HPIPE_PWR_PLL_PHY_MODE_MASK; + data |= 0x4 << HPIPE_PWR_PLL_PHY_MODE_OFFSET; + reg_set(hpipe_addr + HPIPE_PWR_PLL_REG, data, mask); + /* Loopback register */ + mask = HPIPE_LOOPBACK_SEL_MASK; + data = 0x1 << HPIPE_LOOPBACK_SEL_OFFSET; + reg_set(hpipe_addr + HPIPE_LOOPBACK_REG, data, mask); + /* rx control 1 */ + mask = HPIPE_RX_CONTROL_1_RXCLK2X_SEL_MASK; + data = 0x1 << HPIPE_RX_CONTROL_1_RXCLK2X_SEL_OFFSET; + mask |= HPIPE_RX_CONTROL_1_CLK8T_EN_MASK; + data |= 0x0 << HPIPE_RX_CONTROL_1_CLK8T_EN_OFFSET; + reg_set(hpipe_addr + HPIPE_RX_CONTROL_1_REG, data, mask); + /* DTL Control */ + mask = HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK; + data = 0x0 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET; + reg_set(hpipe_addr + HPIPE_PWR_CTR_DTL_REG, data, mask); + + /* Set analog paramters from ETP(HW) - for now use the default datas */ + debug("stage: Analog paramters from ETP(HW)\n"); + + reg_set(hpipe_addr + HPIPE_G1_SET_0_REG, + 0x1 << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET, + HPIPE_G1_SET_0_G1_TX_EMPH1_MASK); + + debug("stage: RFU configurations- Power Up PLL,Tx,Rx\n"); + /* SERDES External Configuration */ + mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK; + data = 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET; + mask |= SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK; + data |= 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET; + mask |= SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK; + data |= 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET; + reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG0_REG, data, mask); + + /* check PLL rx & tx ready */ + addr = sd_ip_addr + SD_EXTERNAL_STATUS0_REG; + data = SD_EXTERNAL_STATUS0_PLL_RX_MASK | + SD_EXTERNAL_STATUS0_PLL_TX_MASK; + mask = data; + data = polling_with_timeout(addr, data, mask, 15000); + if (data != 0) { + debug("Read from reg = %p - value = 0x%x\n", + sd_ip_addr + SD_EXTERNAL_STATUS0_REG, data); + error("SD_EXTERNAL_STATUS0_PLL_RX is %d, SD_EXTERNAL_STATUS0_PLL_TX is %d\n", + (data & SD_EXTERNAL_STATUS0_PLL_RX_MASK), + (data & SD_EXTERNAL_STATUS0_PLL_TX_MASK)); + ret = 0; + } + + /* RX init */ + mask = SD_EXTERNAL_CONFIG1_RX_INIT_MASK; + data = 0x1 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET; + reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask); + + /* check that RX init done */ + addr = sd_ip_addr + SD_EXTERNAL_STATUS0_REG; + data = SD_EXTERNAL_STATUS0_RX_INIT_MASK; + mask = data; + data = polling_with_timeout(addr, data, mask, 100); + if (data != 0) { + debug("Read from reg = %p - value = 0x%x\n", sd_ip_addr + SD_EXTERNAL_STATUS0_REG, data); + error("SD_EXTERNAL_STATUS0_RX_INIT is 0\n"); + ret = 0; + } + + debug("stage: RF Reset\n"); + /* RF Reset */ + mask = SD_EXTERNAL_CONFIG1_RX_INIT_MASK; + data = 0x0 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET; + mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK; + data |= 0x1 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET; + reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask); + + debug_exit(); + return ret; +} + +static int comphy_kr_power_up(u32 lane, void __iomem *hpipe_base, + void __iomem *comphy_base) +{ + u32 mask, data, ret = 1; + void __iomem *hpipe_addr = HPIPE_ADDR(hpipe_base, lane); + void __iomem *sd_ip_addr = SD_ADDR(hpipe_base, lane); + void __iomem *comphy_addr = COMPHY_ADDR(comphy_base, lane); + void __iomem *addr; + + debug_enter(); + debug("stage: RFU configurations - hard reset comphy\n"); + /* RFU configurations - hard reset comphy */ + mask = COMMON_PHY_CFG1_PWR_UP_MASK; + data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET; + mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK; + data |= 0x0 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET; + reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask); + + /* Select Baud Rate of Comphy And PD_PLL/Tx/Rx */ + mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK; + data = 0x0 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET; + mask |= SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_MASK; + data |= 0xE << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET; + mask |= SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_MASK; + data |= 0xE << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET; + mask |= SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK; + data |= 0 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET; + mask |= SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK; + data |= 0 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET; + mask |= SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_MASK; + data |= 0 << SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_OFFSET; + reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG0_REG, data, mask); + + /* release from hard reset */ + mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK; + data = 0x0 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET; + mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK; + data |= 0x0 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET; + mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK; + data |= 0x0 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET; + reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask); + + mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK; + data = 0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET; + mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK; + data |= 0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET; + reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask); + + + /* Wait 1ms - until band gap and ref clock ready */ + mdelay(1); + + /* Start comphy Configuration */ + debug("stage: Comphy configuration\n"); + /* set reference clock */ + mask = HPIPE_MISC_ICP_FORCE_MASK; + data = 0x1 << HPIPE_MISC_ICP_FORCE_OFFSET; + mask |= HPIPE_MISC_REFCLK_SEL_MASK; + data |= 0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET; + reg_set(hpipe_addr + HPIPE_MISC_REG, data, mask); + /* Power and PLL Control */ + mask = HPIPE_PWR_PLL_REF_FREQ_MASK; + data = 0x1 << HPIPE_PWR_PLL_REF_FREQ_OFFSET; + mask |= HPIPE_PWR_PLL_PHY_MODE_MASK; + data |= 0x4 << HPIPE_PWR_PLL_PHY_MODE_OFFSET; + reg_set(hpipe_addr + HPIPE_PWR_PLL_REG, data, mask); + /* Loopback register */ + mask = HPIPE_LOOPBACK_SEL_MASK; + data = 0x1 << HPIPE_LOOPBACK_SEL_OFFSET; + reg_set(hpipe_addr + HPIPE_LOOPBACK_REG, data, mask); + /* rx control 1 */ + mask = HPIPE_RX_CONTROL_1_RXCLK2X_SEL_MASK; + data = 0x1 << HPIPE_RX_CONTROL_1_RXCLK2X_SEL_OFFSET; + mask |= HPIPE_RX_CONTROL_1_CLK8T_EN_MASK; + data |= 0x1 << HPIPE_RX_CONTROL_1_CLK8T_EN_OFFSET; + reg_set(hpipe_addr + HPIPE_RX_CONTROL_1_REG, data, mask); + /* DTL Control */ + mask = HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK; + data = 0x1 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET; + reg_set(hpipe_addr + HPIPE_PWR_CTR_DTL_REG, data, mask); + + /* Set analog paramters from ETP(HW) */ + debug("stage: Analog paramters from ETP(HW)\n"); + /* SERDES External Configuration 2 */ + mask = SD_EXTERNAL_CONFIG2_PIN_DFE_EN_MASK; + data = 0x1 << SD_EXTERNAL_CONFIG2_PIN_DFE_EN_OFFSET; + reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG2_REG, data, mask); + /* 0x7-DFE Resolution control */ + mask = HPIPE_DFE_RES_FORCE_MASK; + data = 0x1 << HPIPE_DFE_RES_FORCE_OFFSET; + reg_set(hpipe_addr + HPIPE_DFE_REG0, data, mask); + /* 0xd-G1_Setting_0 */ + mask = HPIPE_G1_SET_0_G1_TX_AMP_MASK; + data = 0x1c << HPIPE_G1_SET_0_G1_TX_AMP_OFFSET; + mask |= HPIPE_G1_SET_0_G1_TX_EMPH1_MASK; + data |= 0xe << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET; + reg_set(hpipe_addr + HPIPE_G1_SET_0_REG, data, mask); + /* Genration 1 setting 2 (G1_Setting_2) */ + mask = HPIPE_G1_SET_2_G1_TX_EMPH0_MASK; + data = 0x0 << HPIPE_G1_SET_2_G1_TX_EMPH0_OFFSET; + mask |= HPIPE_G1_SET_2_G1_TX_EMPH0_EN_MASK; + data |= 0x1 << HPIPE_G1_SET_2_G1_TX_EMPH0_EN_OFFSET; + reg_set(hpipe_addr + HPIPE_G1_SET_2_REG, data, mask); + /* Transmitter Slew Rate Control register (tx_reg1) */ + mask = HPIPE_TX_REG1_TX_EMPH_RES_MASK; + data = 0x3 << HPIPE_TX_REG1_TX_EMPH_RES_OFFSET; + mask |= HPIPE_TX_REG1_SLC_EN_MASK; + data |= 0x3f << HPIPE_TX_REG1_SLC_EN_OFFSET; + reg_set(hpipe_addr + HPIPE_TX_REG1_REG, data, mask); + /* Impedance Calibration Control register (cal_reg1) */ + mask = HPIPE_CAL_REG_1_EXT_TXIMP_MASK; + data = 0xe << HPIPE_CAL_REG_1_EXT_TXIMP_OFFSET; + mask |= HPIPE_CAL_REG_1_EXT_TXIMP_EN_MASK; + data |= 0x1 << HPIPE_CAL_REG_1_EXT_TXIMP_EN_OFFSET; + reg_set(hpipe_addr + HPIPE_CAL_REG1_REG, data, mask); + /* Generation 1 Setting 5 (g1_setting_5) */ + mask = HPIPE_G1_SETTING_5_G1_ICP_MASK; + data = 0 << HPIPE_CAL_REG_1_EXT_TXIMP_OFFSET; + reg_set(hpipe_addr + HPIPE_G1_SETTING_5_REG, data, mask); + /* 0xE-G1_Setting_1 */ + mask = HPIPE_G1_SET_1_G1_RX_SELMUPI_MASK; + data = 0x1 << HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET; + mask |= HPIPE_G1_SET_1_G1_RX_SELMUPP_MASK; + data |= 0x1 << HPIPE_G1_SET_1_G1_RX_SELMUPP_OFFSET; + mask |= HPIPE_G1_SET_1_G1_RX_DFE_EN_MASK; + data |= 0x1 << HPIPE_G1_SET_1_G1_RX_DFE_EN_OFFSET; + reg_set(hpipe_addr + HPIPE_G1_SET_1_REG, data, mask); + /* 0xA-DFE_Reg3 */ + mask = HPIPE_DFE_F3_F5_DFE_EN_MASK; + data = 0x0 << HPIPE_DFE_F3_F5_DFE_EN_OFFSET; + mask |= HPIPE_DFE_F3_F5_DFE_CTRL_MASK; + data |= 0x0 << HPIPE_DFE_F3_F5_DFE_CTRL_OFFSET; + reg_set(hpipe_addr + HPIPE_DFE_F3_F5_REG, data, mask); + + /* 0x111-G1_Setting_4 */ + mask = HPIPE_G1_SETTINGS_4_G1_DFE_RES_MASK; + data = 0x1 << HPIPE_G1_SETTINGS_4_G1_DFE_RES_OFFSET; + reg_set(hpipe_addr + HPIPE_G1_SETTINGS_4_REG, data, mask); + /* Genration 1 setting 3 (G1_Setting_3) */ + mask = HPIPE_G1_SETTINGS_3_G1_FBCK_SEL_MASK; + data = 0x1 << HPIPE_G1_SETTINGS_3_G1_FBCK_SEL_OFFSET; + reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask); + + debug("stage: RFU configurations- Power Up PLL,Tx,Rx\n"); + /* SERDES External Configuration */ + mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK; + data = 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET; + mask |= SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK; + data |= 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET; + mask |= SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK; + data |= 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET; + reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG0_REG, data, mask); + + + /* check PLL rx & tx ready */ + addr = sd_ip_addr + SD_EXTERNAL_STATUS0_REG; + data = SD_EXTERNAL_STATUS0_PLL_RX_MASK | + SD_EXTERNAL_STATUS0_PLL_TX_MASK; + mask = data; + data = polling_with_timeout(addr, data, mask, 15000); + if (data != 0) { + debug("Read from reg = %p - value = 0x%x\n", sd_ip_addr + SD_EXTERNAL_STATUS0_REG, data); + error("SD_EXTERNAL_STATUS0_PLL_RX is %d, SD_EXTERNAL_STATUS0_PLL_TX is %d\n", + (data & SD_EXTERNAL_STATUS0_PLL_RX_MASK), + (data & SD_EXTERNAL_STATUS0_PLL_TX_MASK)); + ret = 0; + } + + /* RX init */ + mask = SD_EXTERNAL_CONFIG1_RX_INIT_MASK; + data = 0x1 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET; + reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask); + + + /* check that RX init done */ + addr = sd_ip_addr + SD_EXTERNAL_STATUS0_REG; + data = SD_EXTERNAL_STATUS0_RX_INIT_MASK; + mask = data; + data = polling_with_timeout(addr, data, mask, 100); + if (data != 0) { + debug("Read from reg = %p - value = 0x%x\n", + sd_ip_addr + SD_EXTERNAL_STATUS0_REG, data); + error("SD_EXTERNAL_STATUS0_RX_INIT is 0\n"); + ret = 0; + } + + debug("stage: RF Reset\n"); + /* RF Reset */ + mask = SD_EXTERNAL_CONFIG1_RX_INIT_MASK; + data = 0x0 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET; + mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK; + data |= 0x1 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET; + reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask); + + debug_exit(); + return ret; +} + +static int comphy_rxauii_power_up(u32 lane, void __iomem *hpipe_base, + void __iomem *comphy_base) +{ + u32 mask, data, ret = 1; + void __iomem *hpipe_addr = HPIPE_ADDR(hpipe_base, lane); + void __iomem *sd_ip_addr = SD_ADDR(hpipe_base, lane); + void __iomem *comphy_addr = COMPHY_ADDR(comphy_base, lane); + void __iomem *addr; + + debug_enter(); + debug("stage: RFU configurations - hard reset comphy\n"); + /* RFU configurations - hard reset comphy */ + mask = COMMON_PHY_CFG1_PWR_UP_MASK; + data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET; + mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK; + data |= 0x0 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET; + reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask); + + if (lane == 2) { + reg_set(comphy_base + COMMON_PHY_SD_CTRL1, + 0x1 << COMMON_PHY_SD_CTRL1_RXAUI0_OFFSET, + COMMON_PHY_SD_CTRL1_RXAUI0_MASK); + } + if (lane == 4) { + reg_set(comphy_base + COMMON_PHY_SD_CTRL1, + 0x1 << COMMON_PHY_SD_CTRL1_RXAUI1_OFFSET, + COMMON_PHY_SD_CTRL1_RXAUI1_MASK); + } + + /* Select Baud Rate of Comphy And PD_PLL/Tx/Rx */ + mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK; + data = 0x0 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET; + mask |= SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_MASK; + data |= 0xB << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET; + mask |= SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_MASK; + data |= 0xB << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET; + mask |= SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK; + data |= 0x0 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET; + mask |= SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK; + data |= 0x0 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET; + mask |= SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_MASK; + data |= 0x0 << SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_OFFSET; + mask |= SD_EXTERNAL_CONFIG0_MEDIA_MODE_MASK; + data |= 0x1 << SD_EXTERNAL_CONFIG0_MEDIA_MODE_OFFSET; + reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG0_REG, data, mask); + + /* release from hard reset */ + mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK; + data = 0x0 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET; + mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK; + data |= 0x0 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET; + mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK; + data |= 0x0 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET; + reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask); + + mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK; + data = 0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET; + mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK; + data |= 0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET; + reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask); + + /* Wait 1ms - until band gap and ref clock ready */ + mdelay(1); + + /* Start comphy Configuration */ + debug("stage: Comphy configuration\n"); + /* set reference clock */ + reg_set(hpipe_addr + HPIPE_MISC_REG, + 0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET, + HPIPE_MISC_REFCLK_SEL_MASK); + /* Power and PLL Control */ + mask = HPIPE_PWR_PLL_REF_FREQ_MASK; + data = 0x1 << HPIPE_PWR_PLL_REF_FREQ_OFFSET; + mask |= HPIPE_PWR_PLL_PHY_MODE_MASK; + data |= 0x4 << HPIPE_PWR_PLL_PHY_MODE_OFFSET; + reg_set(hpipe_addr + HPIPE_PWR_PLL_REG, data, mask); + /* Loopback register */ + reg_set(hpipe_addr + HPIPE_LOOPBACK_REG, + 0x1 << HPIPE_LOOPBACK_SEL_OFFSET, HPIPE_LOOPBACK_SEL_MASK); + /* rx control 1 */ + mask = HPIPE_RX_CONTROL_1_RXCLK2X_SEL_MASK; + data = 0x1 << HPIPE_RX_CONTROL_1_RXCLK2X_SEL_OFFSET; + mask |= HPIPE_RX_CONTROL_1_CLK8T_EN_MASK; + data |= 0x1 << HPIPE_RX_CONTROL_1_CLK8T_EN_OFFSET; + reg_set(hpipe_addr + HPIPE_RX_CONTROL_1_REG, data, mask); + /* DTL Control */ + reg_set(hpipe_addr + HPIPE_PWR_CTR_DTL_REG, + 0x0 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET, + HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK); + + /* Set analog paramters from ETP(HW) */ + debug("stage: Analog paramters from ETP(HW)\n"); + /* SERDES External Configuration 2 */ + reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG2_REG, + 0x1 << SD_EXTERNAL_CONFIG2_PIN_DFE_EN_OFFSET, + SD_EXTERNAL_CONFIG2_PIN_DFE_EN_MASK); + /* 0x7-DFE Resolution control */ + reg_set(hpipe_addr + HPIPE_DFE_REG0, 0x1 << HPIPE_DFE_RES_FORCE_OFFSET, + HPIPE_DFE_RES_FORCE_MASK); + /* 0xd-G1_Setting_0 */ + reg_set(hpipe_addr + HPIPE_G1_SET_0_REG, + 0xd << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET, + HPIPE_G1_SET_0_G1_TX_EMPH1_MASK); + /* 0xE-G1_Setting_1 */ + mask = HPIPE_G1_SET_1_G1_RX_SELMUPI_MASK; + data = 0x1 << HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET; + mask |= HPIPE_G1_SET_1_G1_RX_SELMUPP_MASK; + data |= 0x1 << HPIPE_G1_SET_1_G1_RX_SELMUPP_OFFSET; + mask |= HPIPE_G1_SET_1_G1_RX_DFE_EN_MASK; + data |= 0x1 << HPIPE_G1_SET_1_G1_RX_DFE_EN_OFFSET; + reg_set(hpipe_addr + HPIPE_G1_SET_1_REG, data, mask); + /* 0xA-DFE_Reg3 */ + mask = HPIPE_DFE_F3_F5_DFE_EN_MASK; + data = 0x0 << HPIPE_DFE_F3_F5_DFE_EN_OFFSET; + mask |= HPIPE_DFE_F3_F5_DFE_CTRL_MASK; + data |= 0x0 << HPIPE_DFE_F3_F5_DFE_CTRL_OFFSET; + reg_set(hpipe_addr + HPIPE_DFE_F3_F5_REG, data, mask); + + /* 0x111-G1_Setting_4 */ + mask = HPIPE_G1_SETTINGS_4_G1_DFE_RES_MASK; + data = 0x1 << HPIPE_G1_SETTINGS_4_G1_DFE_RES_OFFSET; + reg_set(hpipe_addr + HPIPE_G1_SETTINGS_4_REG, data, mask); + + debug("stage: RFU configurations- Power Up PLL,Tx,Rx\n"); + /* SERDES External Configuration */ + mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK; + data = 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET; + mask |= SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK; + data |= 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET; + mask |= SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK; + data |= 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET; + reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG0_REG, data, mask); + + + /* check PLL rx & tx ready */ + addr = sd_ip_addr + SD_EXTERNAL_STATUS0_REG; + data = SD_EXTERNAL_STATUS0_PLL_RX_MASK | + SD_EXTERNAL_STATUS0_PLL_TX_MASK; + mask = data; + data = polling_with_timeout(addr, data, mask, 15000); + if (data != 0) { + debug("Read from reg = %p - value = 0x%x\n", + sd_ip_addr + SD_EXTERNAL_STATUS0_REG, data); + error("SD_EXTERNAL_STATUS0_PLL_RX is %d, SD_EXTERNAL_STATUS0_PLL_TX is %d\n", + (data & SD_EXTERNAL_STATUS0_PLL_RX_MASK), + (data & SD_EXTERNAL_STATUS0_PLL_TX_MASK)); + ret = 0; + } + + /* RX init */ + reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, + 0x1 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET, + SD_EXTERNAL_CONFIG1_RX_INIT_MASK); + + /* check that RX init done */ + addr = sd_ip_addr + SD_EXTERNAL_STATUS0_REG; + data = SD_EXTERNAL_STATUS0_RX_INIT_MASK; + mask = data; + data = polling_with_timeout(addr, data, mask, 100); + if (data != 0) { + debug("Read from reg = %p - value = 0x%x\n", + sd_ip_addr + SD_EXTERNAL_STATUS0_REG, data); + error("SD_EXTERNAL_STATUS0_RX_INIT is 0\n"); + ret = 0; + } + + debug("stage: RF Reset\n"); + /* RF Reset */ + mask = SD_EXTERNAL_CONFIG1_RX_INIT_MASK; + data = 0x0 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET; + mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK; + data |= 0x1 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET; + reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask); + + debug_exit(); + return ret; +} + +static void comphy_utmi_power_down(u32 utmi_index, void __iomem *utmi_base_addr, + void __iomem *usb_cfg_addr, + void __iomem *utmi_cfg_addr, + u32 utmi_phy_port) +{ + u32 mask, data; + + debug_enter(); + debug("stage: UTMI %d - Power down transceiver (power down Phy), Power down PLL, and SuspendDM\n", + utmi_index); + /* Power down UTMI PHY */ + reg_set(utmi_cfg_addr, 0x0 << UTMI_PHY_CFG_PU_OFFSET, + UTMI_PHY_CFG_PU_MASK); + + /* + * If UTMI connected to USB Device, configure mux prior to PHY init + * (Device can be connected to UTMI0 or to UTMI1) + */ + if (utmi_phy_port == UTMI_PHY_TO_USB_DEVICE0) { + debug("stage: UTMI %d - Enable Device mode and configure UTMI mux\n", + utmi_index); + /* USB3 Device UTMI enable */ + mask = UTMI_USB_CFG_DEVICE_EN_MASK; + data = 0x1 << UTMI_USB_CFG_DEVICE_EN_OFFSET; + /* USB3 Device UTMI MUX */ + mask |= UTMI_USB_CFG_DEVICE_MUX_MASK; + data |= utmi_index << UTMI_USB_CFG_DEVICE_MUX_OFFSET; + reg_set(usb_cfg_addr, data, mask); + } + + /* Set Test suspendm mode */ + mask = UTMI_CTRL_STATUS0_SUSPENDM_MASK; + data = 0x1 << UTMI_CTRL_STATUS0_SUSPENDM_OFFSET; + /* Enable Test UTMI select */ + mask |= UTMI_CTRL_STATUS0_TEST_SEL_MASK; + data |= 0x1 << UTMI_CTRL_STATUS0_TEST_SEL_OFFSET; + reg_set(utmi_base_addr + UTMI_CTRL_STATUS0_REG, data, mask); + + /* Wait for UTMI power down */ + mdelay(1); + + debug_exit(); + return; +} + +static void comphy_utmi_phy_config(u32 utmi_index, void __iomem *utmi_base_addr, + void __iomem *usb_cfg_addr, + void __iomem *utmi_cfg_addr, + u32 utmi_phy_port) +{ + u32 mask, data; + + debug_exit(); + debug("stage: Configure UTMI PHY %d registers\n", utmi_index); + /* Reference Clock Divider Select */ + mask = UTMI_PLL_CTRL_REFDIV_MASK; + data = 0x5 << UTMI_PLL_CTRL_REFDIV_OFFSET; + /* Feedback Clock Divider Select - 90 for 25Mhz*/ + mask |= UTMI_PLL_CTRL_FBDIV_MASK; + data |= 0x60 << UTMI_PLL_CTRL_FBDIV_OFFSET; + /* Select LPFR - 0x0 for 25Mhz/5=5Mhz*/ + mask |= UTMI_PLL_CTRL_SEL_LPFR_MASK; + data |= 0x0 << UTMI_PLL_CTRL_SEL_LPFR_OFFSET; + reg_set(utmi_base_addr + UTMI_PLL_CTRL_REG, data, mask); + + /* Impedance Calibration Threshold Setting */ + reg_set(utmi_base_addr + UTMI_CALIB_CTRL_REG, + 0x6 << UTMI_CALIB_CTRL_IMPCAL_VTH_OFFSET, + UTMI_CALIB_CTRL_IMPCAL_VTH_MASK); + + /* Set LS TX driver strength coarse control */ + mask = UTMI_TX_CH_CTRL_DRV_EN_LS_MASK; + data = 0x3 << UTMI_TX_CH_CTRL_DRV_EN_LS_OFFSET; + /* Set LS TX driver fine adjustment */ + mask |= UTMI_TX_CH_CTRL_IMP_SEL_LS_MASK; + data |= 0x3 << UTMI_TX_CH_CTRL_IMP_SEL_LS_OFFSET; + reg_set(utmi_base_addr + UTMI_TX_CH_CTRL_REG, data, mask); + + /* Enable SQ */ + mask = UTMI_RX_CH_CTRL0_SQ_DET_MASK; + data = 0x0 << UTMI_RX_CH_CTRL0_SQ_DET_OFFSET; + /* Enable analog squelch detect */ + mask |= UTMI_RX_CH_CTRL0_SQ_ANA_DTC_MASK; + data |= 0x1 << UTMI_RX_CH_CTRL0_SQ_ANA_DTC_OFFSET; + reg_set(utmi_base_addr + UTMI_RX_CH_CTRL0_REG, data, mask); + + /* Set External squelch calibration number */ + mask = UTMI_RX_CH_CTRL1_SQ_AMP_CAL_MASK; + data = 0x1 << UTMI_RX_CH_CTRL1_SQ_AMP_CAL_OFFSET; + /* Enable the External squelch calibration */ + mask |= UTMI_RX_CH_CTRL1_SQ_AMP_CAL_EN_MASK; + data |= 0x1 << UTMI_RX_CH_CTRL1_SQ_AMP_CAL_EN_OFFSET; + reg_set(utmi_base_addr + UTMI_RX_CH_CTRL1_REG, data, mask); + + /* Set Control VDAT Reference Voltage - 0.325V */ + mask = UTMI_CHGDTC_CTRL_VDAT_MASK; + data = 0x1 << UTMI_CHGDTC_CTRL_VDAT_OFFSET; + /* Set Control VSRC Reference Voltage - 0.6V */ + mask |= UTMI_CHGDTC_CTRL_VSRC_MASK; + data |= 0x1 << UTMI_CHGDTC_CTRL_VSRC_OFFSET; + reg_set(utmi_base_addr + UTMI_CHGDTC_CTRL_REG, data, mask); + + debug_exit(); + return; +} + +static int comphy_utmi_power_up(u32 utmi_index, void __iomem *utmi_base_addr, + void __iomem *usb_cfg_addr, + void __iomem *utmi_cfg_addr, u32 utmi_phy_port) +{ + u32 data, mask, ret = 1; + void __iomem *addr; + + debug_enter(); + debug("stage: UTMI %d - Power up transceiver(Power up Phy), and exit SuspendDM\n", + utmi_index); + /* Power UP UTMI PHY */ + reg_set(utmi_cfg_addr, 0x1 << UTMI_PHY_CFG_PU_OFFSET, + UTMI_PHY_CFG_PU_MASK); + /* Disable Test UTMI select */ + reg_set(utmi_base_addr + UTMI_CTRL_STATUS0_REG, + 0x0 << UTMI_CTRL_STATUS0_TEST_SEL_OFFSET, + UTMI_CTRL_STATUS0_TEST_SEL_MASK); + + debug("stage: Polling for PLL and impedance calibration done, and PLL ready done\n"); + addr = utmi_base_addr + UTMI_CALIB_CTRL_REG; + data = UTMI_CALIB_CTRL_IMPCAL_DONE_MASK; + mask = data; + data = polling_with_timeout(addr, data, mask, 100); + if (data != 0) { + error("Impedance calibration is not done\n"); + debug("Read from reg = %p - value = 0x%x\n", addr, data); + ret = 0; + } + + data = UTMI_CALIB_CTRL_PLLCAL_DONE_MASK; + mask = data; + data = polling_with_timeout(addr, data, mask, 100); + if (data != 0) { + error("PLL calibration is not done\n"); + debug("Read from reg = %p - value = 0x%x\n", addr, data); + ret = 0; + } + + addr = utmi_base_addr + UTMI_PLL_CTRL_REG; + data = UTMI_PLL_CTRL_PLL_RDY_MASK; + mask = data; + data = polling_with_timeout(addr, data, mask, 100); + if (data != 0) { + error("PLL is not ready\n"); + debug("Read from reg = %p - value = 0x%x\n", addr, data); + ret = 0; + } + + if (ret) + debug("Passed\n"); + else + debug("\n"); + + debug_exit(); + return ret; +} + +/* + * comphy_utmi_phy_init initialize the UTMI PHY + * the init split in 3 parts: + * 1. Power down transceiver and PLL + * 2. UTMI PHY configure + * 3. Powe up transceiver and PLL + * Note: - Power down/up should be once for both UTMI PHYs + * - comphy_dedicated_phys_init call this function if at least there is + * one UTMI PHY exists in FDT blob. access to cp110_utmi_data[0] is + * legal + */ +static void comphy_utmi_phy_init(u32 utmi_phy_count, + struct utmi_phy_data *cp110_utmi_data) +{ + u32 i; + + debug_enter(); + /* UTMI Power down */ + for (i = 0; i < utmi_phy_count; i++) { + comphy_utmi_power_down(i, cp110_utmi_data[i].utmi_base_addr, + cp110_utmi_data[i].usb_cfg_addr, + cp110_utmi_data[i].utmi_cfg_addr, + cp110_utmi_data[i].utmi_phy_port); + } + /* PLL Power down */ + debug("stage: UTMI PHY power down PLL\n"); + for (i = 0; i < utmi_phy_count; i++) { + reg_set(cp110_utmi_data[i].usb_cfg_addr, + 0x0 << UTMI_USB_CFG_PLL_OFFSET, UTMI_USB_CFG_PLL_MASK); + } + /* UTMI configure */ + for (i = 0; i < utmi_phy_count; i++) { + comphy_utmi_phy_config(i, cp110_utmi_data[i].utmi_base_addr, + cp110_utmi_data[i].usb_cfg_addr, + cp110_utmi_data[i].utmi_cfg_addr, + cp110_utmi_data[i].utmi_phy_port); + } + /* UTMI Power up */ + for (i = 0; i < utmi_phy_count; i++) { + if (!comphy_utmi_power_up(i, cp110_utmi_data[i].utmi_base_addr, + cp110_utmi_data[i].usb_cfg_addr, + cp110_utmi_data[i].utmi_cfg_addr, + cp110_utmi_data[i].utmi_phy_port)) { + error("Failed to initialize UTMI PHY %d\n", i); + continue; + } + printf("UTMI PHY %d initialized to ", i); + if (cp110_utmi_data[i].utmi_phy_port == UTMI_PHY_TO_USB_DEVICE0) + printf("USB Device\n"); + else + printf("USB Host%d\n", + cp110_utmi_data[i].utmi_phy_port); + } + /* PLL Power up */ + debug("stage: UTMI PHY power up PLL\n"); + for (i = 0; i < utmi_phy_count; i++) { + reg_set(cp110_utmi_data[i].usb_cfg_addr, + 0x1 << UTMI_USB_CFG_PLL_OFFSET, UTMI_USB_CFG_PLL_MASK); + } + + debug_exit(); + return; +} + +/* + * comphy_dedicated_phys_init initialize the dedicated PHYs + * - not muxed SerDes lanes e.g. UTMI PHY + */ +void comphy_dedicated_phys_init(void) +{ + struct utmi_phy_data cp110_utmi_data[MAX_UTMI_PHY_COUNT]; + int node; + int i; + + debug_enter(); + debug("Initialize USB UTMI PHYs\n"); + + /* Find the UTMI phy node in device tree and go over them */ + node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, + "marvell,mvebu-utmi-2.6.0"); + + i = 0; + while (node > 0) { + /* get base address of UTMI phy */ + cp110_utmi_data[i].utmi_base_addr = + (void __iomem *)fdtdec_get_addr_size_auto_noparent( + gd->fdt_blob, node, "reg", 0, NULL, true); + if (cp110_utmi_data[i].utmi_base_addr == NULL) { + error("UTMI PHY base address is invalid\n"); + i++; + continue; + } + + /* get usb config address */ + cp110_utmi_data[i].usb_cfg_addr = + (void __iomem *)fdtdec_get_addr_size_auto_noparent( + gd->fdt_blob, node, "reg", 1, NULL, true); + if (cp110_utmi_data[i].usb_cfg_addr == NULL) { + error("UTMI PHY base address is invalid\n"); + i++; + continue; + } + + /* get UTMI config address */ + cp110_utmi_data[i].utmi_cfg_addr = + (void __iomem *)fdtdec_get_addr_size_auto_noparent( + gd->fdt_blob, node, "reg", 2, NULL, true); + if (cp110_utmi_data[i].utmi_cfg_addr == NULL) { + error("UTMI PHY base address is invalid\n"); + i++; + continue; + } + + /* + * get the port number (to check if the utmi connected to + * host/device) + */ + cp110_utmi_data[i].utmi_phy_port = fdtdec_get_int( + gd->fdt_blob, node, "utmi-port", UTMI_PHY_INVALID); + if (cp110_utmi_data[i].utmi_phy_port == UTMI_PHY_INVALID) { + error("UTMI PHY port type is invalid\n"); + i++; + continue; + } + + node = fdt_node_offset_by_compatible( + gd->fdt_blob, node, "marvell,mvebu-utmi-2.6.0"); + i++; + } + + if (i > 0) + comphy_utmi_phy_init(i, cp110_utmi_data); + + debug_exit(); +} + +static void comphy_mux_cp110_init(struct chip_serdes_phy_config *ptr_chip_cfg, + struct comphy_map *serdes_map) +{ + void __iomem *comphy_base_addr; + struct comphy_map comphy_map_pipe_data[MAX_LANE_OPTIONS]; + struct comphy_map comphy_map_phy_data[MAX_LANE_OPTIONS]; + u32 lane, comphy_max_count; + + comphy_max_count = ptr_chip_cfg->comphy_lanes_count; + comphy_base_addr = ptr_chip_cfg->comphy_base_addr; + + /* + * Copy the SerDes map configuration for PIPE map and PHY map + * the comphy_mux_init modify the type of the lane if the type + * is not valid because we have 2 selectores run the + * comphy_mux_init twice and after that update the original + * serdes_map + */ + for (lane = 0; lane < comphy_max_count; lane++) { + comphy_map_pipe_data[lane].type = serdes_map[lane].type; + comphy_map_pipe_data[lane].speed = serdes_map[lane].speed; + comphy_map_phy_data[lane].type = serdes_map[lane].type; + comphy_map_phy_data[lane].speed = serdes_map[lane].speed; + } + ptr_chip_cfg->mux_data = cp110_comphy_phy_mux_data; + comphy_mux_init(ptr_chip_cfg, comphy_map_phy_data, + comphy_base_addr + COMMON_SELECTOR_PHY_OFFSET); + + ptr_chip_cfg->mux_data = cp110_comphy_pipe_mux_data; + comphy_mux_init(ptr_chip_cfg, comphy_map_pipe_data, + comphy_base_addr + COMMON_SELECTOR_PIPE_OFFSET); + /* Fix the type after check the PHY and PIPE configuration */ + for (lane = 0; lane < comphy_max_count; lane++) { + if ((comphy_map_pipe_data[lane].type == PHY_TYPE_UNCONNECTED) && + (comphy_map_phy_data[lane].type == PHY_TYPE_UNCONNECTED)) + serdes_map[lane].type = PHY_TYPE_UNCONNECTED; + } +} + +int comphy_cp110_init(struct chip_serdes_phy_config *ptr_chip_cfg, + struct comphy_map *serdes_map) +{ + struct comphy_map *ptr_comphy_map; + void __iomem *comphy_base_addr, *hpipe_base_addr; + u32 comphy_max_count, lane, ret = 0; + u32 pcie_width = 0; + + debug_enter(); + + comphy_max_count = ptr_chip_cfg->comphy_lanes_count; + comphy_base_addr = ptr_chip_cfg->comphy_base_addr; + hpipe_base_addr = ptr_chip_cfg->hpipe3_base_addr; + + /* Config Comphy mux configuration */ + comphy_mux_cp110_init(ptr_chip_cfg, serdes_map); + + /* Check if the first 4 lanes configured as By-4 */ + for (lane = 0, ptr_comphy_map = serdes_map; lane < 4; + lane++, ptr_comphy_map++) { + if (ptr_comphy_map->type != PHY_TYPE_PEX0) + break; + pcie_width++; + } + + for (lane = 0, ptr_comphy_map = serdes_map; lane < comphy_max_count; + lane++, ptr_comphy_map++) { + debug("Initialize serdes number %d\n", lane); + debug("Serdes type = 0x%x\n", ptr_comphy_map->type); + if (lane == 4) { + /* + * PCIe lanes above the first 4 lanes, can be only + * by1 + */ + pcie_width = 1; + } + switch (ptr_comphy_map->type) { + case PHY_TYPE_UNCONNECTED: + continue; + break; + case PHY_TYPE_PEX0: + case PHY_TYPE_PEX1: + case PHY_TYPE_PEX2: + case PHY_TYPE_PEX3: + ret = comphy_pcie_power_up( + lane, pcie_width, ptr_comphy_map->clk_src, + hpipe_base_addr, comphy_base_addr); + break; + case PHY_TYPE_SATA0: + case PHY_TYPE_SATA1: + case PHY_TYPE_SATA2: + case PHY_TYPE_SATA3: + ret = comphy_sata_power_up( + lane, hpipe_base_addr, comphy_base_addr, + ptr_chip_cfg->comphy_index); + break; + case PHY_TYPE_USB3_HOST0: + case PHY_TYPE_USB3_HOST1: + case PHY_TYPE_USB3_DEVICE: + ret = comphy_usb3_power_up(lane, hpipe_base_addr, + comphy_base_addr); + break; + case PHY_TYPE_SGMII0: + case PHY_TYPE_SGMII1: + case PHY_TYPE_SGMII2: + case PHY_TYPE_SGMII3: + if (ptr_comphy_map->speed == PHY_SPEED_INVALID) { + debug("Warning: SGMII PHY speed in lane %d is invalid, set PHY speed to 1.25G\n", + lane); + ptr_comphy_map->speed = PHY_SPEED_1_25G; + } + ret = comphy_sgmii_power_up( + lane, ptr_comphy_map->speed, hpipe_base_addr, + comphy_base_addr); + break; + case PHY_TYPE_KR: + ret = comphy_kr_power_up(lane, hpipe_base_addr, + comphy_base_addr); + break; + case PHY_TYPE_RXAUI0: + case PHY_TYPE_RXAUI1: + ret = comphy_rxauii_power_up(lane, hpipe_base_addr, + comphy_base_addr); + break; + default: + debug("Unknown SerDes type, skip initialize SerDes %d\n", + lane); + break; + } + if (ret == 0) { + /* + * If interface wans't initialiuzed, set the lane to + * PHY_TYPE_UNCONNECTED state. + */ + ptr_comphy_map->type = PHY_TYPE_UNCONNECTED; + error("PLL is not locked - Failed to initialize lane %d\n", + lane); + } + } + + debug_exit(); + return 0; +} diff --git a/drivers/phy/marvell/comphy_hpipe.h b/drivers/phy/marvell/comphy_hpipe.h index 0c9b500..179e910 100644 --- a/drivers/phy/marvell/comphy_hpipe.h +++ b/drivers/phy/marvell/comphy_hpipe.h @@ -78,6 +78,14 @@ #define HPIPE_KVCO_CALIB_CTRL_MAX_PLL_MASK \ (0x1 << HPIPE_KVCO_CALIB_CTRL_MAX_PLL_OFFSET) +#define HPIPE_CAL_REG1_REG 0xc +#define HPIPE_CAL_REG_1_EXT_TXIMP_OFFSET 10 +#define HPIPE_CAL_REG_1_EXT_TXIMP_MASK \ + (0x1f << HPIPE_CAL_REG_1_EXT_TXIMP_OFFSET) +#define HPIPE_CAL_REG_1_EXT_TXIMP_EN_OFFSET 15 +#define HPIPE_CAL_REG_1_EXT_TXIMP_EN_MASK \ + (0x1 << HPIPE_CAL_REG_1_EXT_TXIMP_EN_OFFSET) + #define HPIPE_SQUELCH_FFE_SETTING_REG 0x018 #define HPIPE_DFE_REG0 0x01C @@ -94,6 +102,9 @@ (0x1 << HPIPE_DFE_F3_F5_DFE_CTRL_OFFSET) #define HPIPE_G1_SET_0_REG 0x034 +#define HPIPE_G1_SET_0_G1_TX_AMP_OFFSET 1 +#define HPIPE_G1_SET_0_G1_TX_AMP_MASK \ + (0x1f << HPIPE_G1_SET_0_G1_TX_AMP_OFFSET) #define HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET 7 #define HPIPE_G1_SET_0_G1_TX_EMPH1_MASK \ (0xf << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET) @@ -145,6 +156,14 @@ #define HPIPE_ISOLATE_MODE_GEN_TX_MASK \ (0xf << HPIPE_ISOLATE_MODE_GEN_TX_OFFSET) +#define HPIPE_G1_SET_2_REG 0xf4 +#define HPIPE_G1_SET_2_G1_TX_EMPH0_OFFSET 0 +#define HPIPE_G1_SET_2_G1_TX_EMPH0_MASK \ + (0xf << HPIPE_G1_SET_2_G1_TX_EMPH0_OFFSET) +#define HPIPE_G1_SET_2_G1_TX_EMPH0_EN_OFFSET 4 +#define HPIPE_G1_SET_2_G1_TX_EMPH0_EN_MASK \ + (0x1 << HPIPE_G1_SET_2_G1_TX_EMPH0_MASK) + #define HPIPE_VTHIMPCAL_CTRL_REG 0x104 #define HPIPE_PCIE_REG0 0x120 @@ -164,6 +183,9 @@ #define HPIPE_MISC_CLK100M_125M_OFFSET 4 #define HPIPE_MISC_CLK100M_125M_MASK \ (0x1 << HPIPE_MISC_CLK100M_125M_OFFSET) +#define HPIPE_MISC_ICP_FORCE_OFFSET 5 +#define HPIPE_MISC_ICP_FORCE_MASK \ + (0x1 << HPIPE_MISC_ICP_FORCE_OFFSET) #define HPIPE_MISC_TXDCLK_2X_OFFSET 6 #define HPIPE_MISC_TXDCLK_2X_MASK \ (0x1 << HPIPE_MISC_TXDCLK_2X_OFFSET) @@ -197,6 +219,14 @@ #define HPIPE_SMAPLER_MASK \ (0x1 << HPIPE_SMAPLER_OFFSET) +#define HPIPE_TX_REG1_REG 0x174 +#define HPIPE_TX_REG1_TX_EMPH_RES_OFFSET 5 +#define HPIPE_TX_REG1_TX_EMPH_RES_MASK \ + (0x3 << HPIPE_TX_REG1_TX_EMPH_RES_OFFSET) +#define HPIPE_TX_REG1_SLC_EN_OFFSET 10 +#define HPIPE_TX_REG1_SLC_EN_MASK \ + (0x3f << HPIPE_TX_REG1_SLC_EN_OFFSET) + #define HPIPE_PWR_CTR_DTL_REG 0x184 #define HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET 2 #define HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK \ @@ -262,6 +292,9 @@ (0x1 << HPIPE_TX_SWEEP_PRESET_EN_OFFSET) #define HPIPE_G1_SETTINGS_3_REG 0x440 +#define HPIPE_G1_SETTINGS_3_G1_FBCK_SEL_OFFSET 9 +#define HPIPE_G1_SETTINGS_3_G1_FBCK_SEL_MASK \ + (0x1 << HPIPE_G1_SETTINGS_3_G1_FBCK_SEL_OFFSET) #define HPIPE_G1_SETTINGS_4_REG 0x444 #define HPIPE_G1_SETTINGS_4_G1_DFE_RES_OFFSET 8 @@ -289,6 +322,11 @@ #define HPIPE_DFE_CTRL_28_PIPE4_MASK \ (0x1 << HPIPE_DFE_CTRL_28_PIPE4_OFFSET) +#define HPIPE_G1_SETTING_5_REG 0x538 +#define HPIPE_G1_SETTING_5_G1_ICP_OFFSET 0 +#define HPIPE_G1_SETTING_5_G1_ICP_MASK \ + (0xf << HPIPE_G1_SETTING_5_G1_ICP_OFFSET) + #define HPIPE_LANE_CONFIG0_REG 0x600 #define HPIPE_LANE_CONFIG0_TXDEEMPH0_OFFSET 0 #define HPIPE_LANE_CONFIG0_TXDEEMPH0_MASK \ diff --git a/drivers/phy/marvell/sata.h b/drivers/phy/marvell/sata.h new file mode 100644 index 0000000..be2ba54 --- /dev/null +++ b/drivers/phy/marvell/sata.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2015-2016 Marvell International Ltd. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _SATA_H_ +#define _SATA_H_ + +/* SATA3 Unit address */ +#define SATA3_VENDOR_ADDRESS 0xA0 +#define SATA3_VENDOR_ADDR_OFSSET 0 +#define SATA3_VENDOR_ADDR_MASK (0xFFFFFFFF << SATA3_VENDOR_ADDR_OFSSET) +#define SATA3_VENDOR_DATA 0xA4 + +#define SATA_CONTROL_REG 0x0 +#define SATA3_CTRL_SATA0_PD_OFFSET 6 +#define SATA3_CTRL_SATA0_PD_MASK (1 << SATA3_CTRL_SATA0_PD_OFFSET) +#define SATA3_CTRL_SATA1_PD_OFFSET 14 +#define SATA3_CTRL_SATA1_PD_MASK (1 << SATA3_CTRL_SATA1_PD_OFFSET) +#define SATA3_CTRL_SATA1_ENABLE_OFFSET 22 +#define SATA3_CTRL_SATA1_ENABLE_MASK (1 << SATA3_CTRL_SATA1_ENABLE_OFFSET) +#define SATA3_CTRL_SATA_SSU_OFFSET 23 +#define SATA3_CTRL_SATA_SSU_MASK (1 << SATA3_CTRL_SATA_SSU_OFFSET) + +#define SATA_MBUS_SIZE_SELECT_REG 0x4 +#define SATA_MBUS_REGRET_EN_OFFSET 7 +#define SATA_MBUS_REGRET_EN_MASK (0x1 << SATA_MBUS_REGRET_EN_OFFSET) + +#endif /* _SATA_H_ */ diff --git a/drivers/phy/marvell/utmi_phy.h b/drivers/phy/marvell/utmi_phy.h new file mode 100644 index 0000000..01e53ba --- /dev/null +++ b/drivers/phy/marvell/utmi_phy.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2015-2016 Marvell International Ltd. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _UTMI_PHY_H_ +#define _UTMI_PHY_H_ + +#define UTMI_USB_CFG_DEVICE_EN_OFFSET 0 +#define UTMI_USB_CFG_DEVICE_EN_MASK \ + (0x1 << UTMI_USB_CFG_DEVICE_EN_OFFSET) +#define UTMI_USB_CFG_DEVICE_MUX_OFFSET 1 +#define UTMI_USB_CFG_DEVICE_MUX_MASK \ + (0x1 << UTMI_USB_CFG_DEVICE_MUX_OFFSET) +#define UTMI_USB_CFG_PLL_OFFSET 25 +#define UTMI_USB_CFG_PLL_MASK \ + (0x1 << UTMI_USB_CFG_PLL_OFFSET) + +#define UTMI_PHY_CFG_PU_OFFSET 5 +#define UTMI_PHY_CFG_PU_MASK \ + (0x1 << UTMI_PHY_CFG_PU_OFFSET) + +#define UTMI_PLL_CTRL_REG 0x0 +#define UTMI_PLL_CTRL_REFDIV_OFFSET 0 +#define UTMI_PLL_CTRL_REFDIV_MASK \ + (0x7f << UTMI_PLL_CTRL_REFDIV_OFFSET) +#define UTMI_PLL_CTRL_FBDIV_OFFSET 16 +#define UTMI_PLL_CTRL_FBDIV_MASK \ + (0x1FF << UTMI_PLL_CTRL_FBDIV_OFFSET) +#define UTMI_PLL_CTRL_SEL_LPFR_OFFSET 28 +#define UTMI_PLL_CTRL_SEL_LPFR_MASK \ + (0x3 << UTMI_PLL_CTRL_SEL_LPFR_OFFSET) +#define UTMI_PLL_CTRL_PLL_RDY_OFFSET 31 +#define UTMI_PLL_CTRL_PLL_RDY_MASK \ + (0x1 << UTMI_PLL_CTRL_PLL_RDY_OFFSET) + +#define UTMI_CALIB_CTRL_REG 0x8 +#define UTMI_CALIB_CTRL_IMPCAL_VTH_OFFSET 8 +#define UTMI_CALIB_CTRL_IMPCAL_VTH_MASK \ + (0x7 << UTMI_CALIB_CTRL_IMPCAL_VTH_OFFSET) +#define UTMI_CALIB_CTRL_IMPCAL_DONE_OFFSET 23 +#define UTMI_CALIB_CTRL_IMPCAL_DONE_MASK \ + (0x1 << UTMI_CALIB_CTRL_IMPCAL_DONE_OFFSET) +#define UTMI_CALIB_CTRL_PLLCAL_DONE_OFFSET 31 +#define UTMI_CALIB_CTRL_PLLCAL_DONE_MASK \ + (0x1 << UTMI_CALIB_CTRL_PLLCAL_DONE_OFFSET) + +#define UTMI_TX_CH_CTRL_REG 0xC +#define UTMI_TX_CH_CTRL_DRV_EN_LS_OFFSET 12 +#define UTMI_TX_CH_CTRL_DRV_EN_LS_MASK \ + (0xf << UTMI_TX_CH_CTRL_DRV_EN_LS_OFFSET) +#define UTMI_TX_CH_CTRL_IMP_SEL_LS_OFFSET 16 +#define UTMI_TX_CH_CTRL_IMP_SEL_LS_MASK \ + (0xf << UTMI_TX_CH_CTRL_IMP_SEL_LS_OFFSET) + +#define UTMI_RX_CH_CTRL0_REG 0x14 +#define UTMI_RX_CH_CTRL0_SQ_DET_OFFSET 15 +#define UTMI_RX_CH_CTRL0_SQ_DET_MASK \ + (0x1 << UTMI_RX_CH_CTRL0_SQ_DET_OFFSET) +#define UTMI_RX_CH_CTRL0_SQ_ANA_DTC_OFFSET 28 +#define UTMI_RX_CH_CTRL0_SQ_ANA_DTC_MASK \ + (0x1 << UTMI_RX_CH_CTRL0_SQ_ANA_DTC_OFFSET) + +#define UTMI_RX_CH_CTRL1_REG 0x18 +#define UTMI_RX_CH_CTRL1_SQ_AMP_CAL_OFFSET 0 +#define UTMI_RX_CH_CTRL1_SQ_AMP_CAL_MASK \ + (0x3 << UTMI_RX_CH_CTRL1_SQ_AMP_CAL_OFFSET) +#define UTMI_RX_CH_CTRL1_SQ_AMP_CAL_EN_OFFSET 3 +#define UTMI_RX_CH_CTRL1_SQ_AMP_CAL_EN_MASK \ + (0x1 << UTMI_RX_CH_CTRL1_SQ_AMP_CAL_EN_OFFSET) + +#define UTMI_CTRL_STATUS0_REG 0x24 +#define UTMI_CTRL_STATUS0_SUSPENDM_OFFSET 22 +#define UTMI_CTRL_STATUS0_SUSPENDM_MASK \ + (0x1 << UTMI_CTRL_STATUS0_SUSPENDM_OFFSET) +#define UTMI_CTRL_STATUS0_TEST_SEL_OFFSET 25 +#define UTMI_CTRL_STATUS0_TEST_SEL_MASK \ + (0x1 << UTMI_CTRL_STATUS0_TEST_SEL_OFFSET) + +#define UTMI_CHGDTC_CTRL_REG 0x38 +#define UTMI_CHGDTC_CTRL_VDAT_OFFSET 8 +#define UTMI_CHGDTC_CTRL_VDAT_MASK \ + (0x3 << UTMI_CHGDTC_CTRL_VDAT_OFFSET) +#define UTMI_CHGDTC_CTRL_VSRC_OFFSET 10 +#define UTMI_CHGDTC_CTRL_VSRC_MASK \ + (0x3 << UTMI_CHGDTC_CTRL_VSRC_OFFSET) + +#endif /* _UTMI_PHY_H_ */ + -- cgit v1.1 From d36277ef4f5b297e5d404d1ad19123b02dc539d1 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Wed, 31 Aug 2016 06:48:56 +0200 Subject: usb: xhci-mvebu: Add Armada 8K to compatiblity list To enable this driver on Armada 7K/8K this patch adds the compatibility property to the list. Signed-off-by: Stefan Roese Cc: Nadav Haklai Cc: Neta Zur Hershkovits Cc: Kostya Porotchkin Cc: Omri Itach Cc: Igal Liberman Cc: Haim Boot Cc: Hanna Hawa --- drivers/usb/host/xhci-mvebu.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-mvebu.c b/drivers/usb/host/xhci-mvebu.c index e09e87a..23c241a 100644 --- a/drivers/usb/host/xhci-mvebu.c +++ b/drivers/usb/host/xhci-mvebu.c @@ -79,6 +79,7 @@ static int xhci_usb_ofdata_to_platdata(struct udevice *dev) static const struct udevice_id xhci_usb_ids[] = { { .compatible = "marvell,armada3700-xhci" }, + { .compatible = "marvell,armada-8k-xhci" }, { } }; -- cgit v1.1 From 22f5de6b5cf381acf63b49655cb3d7cb5bf684ab Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Wed, 31 Aug 2016 10:02:15 +0200 Subject: ahci: Make ahci_port_base() non-static to enable overwrite To allow a board- / platform-specific ahci_port_base() function, this patch removes "static inline" and adds __weak to this function. This will be used by the upcoming Armada 7K/8K SATA / AHCI support, which unfortunately needs a different port base address calculation. Signed-off-by: Stefan Roese Cc: Nadav Haklai Cc: Neta Zur Hershkovits Cc: Kostya Porotchkin Cc: Omri Itach Cc: Igal Liberman Cc: Haim Boot Cc: Hanna Hawa --- drivers/block/ahci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c index 2e1ddf9..5139989 100644 --- a/drivers/block/ahci.c +++ b/drivers/block/ahci.c @@ -45,7 +45,7 @@ u16 *ataid[AHCI_MAX_PORTS]; #define WAIT_MS_FLUSH 5000 #define WAIT_MS_LINKUP 200 -static inline void __iomem *ahci_port_base(void __iomem *base, u32 port) +__weak void __iomem *ahci_port_base(void __iomem *base, u32 port) { return base + 0x100 + (port * 0x80); } -- cgit v1.1