1406 lines
41 KiB
C
1406 lines
41 KiB
C
/*
|
|
* (c) 2010 STMicroelectronics Limited
|
|
*
|
|
* Author: Pawel Moll <pawel.moll@st.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/init.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/ethtool.h>
|
|
#include <linux/dma-mapping.h>
|
|
#include <linux/phy.h>
|
|
#include <linux/stm/miphy.h>
|
|
#include <linux/stm/device.h>
|
|
#include <linux/stm/sysconf.h>
|
|
#include <linux/stm/emi.h>
|
|
#include <linux/stm/stx7108.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/clk.h>
|
|
#include <asm/irq-ilc.h>
|
|
|
|
/* --------------------------------------------------------------------
|
|
* Ethernet MAC resources (PAD and Retiming)
|
|
* --------------------------------------------------------------------*/
|
|
|
|
|
|
#undef DEBUG_RETIME_CONF
|
|
/* Turn-on to only debug retiming setting for example on eth driver */
|
|
/*#define DEBUG_RETIME_CONF*/
|
|
|
|
#define ETH_MDIO_BIDIR(_gmac, _port, _pin, _retiming) \
|
|
{ \
|
|
.gpio = stm_gpio(_port, _pin), \
|
|
.direction = stm_pad_gpio_direction_custom, \
|
|
.function = 1 + _gmac, \
|
|
.priv = &(struct stx7108_pio_config) { \
|
|
.retime = &_retiming, \
|
|
.mode = &(struct stx7108_pio_mode_config) { \
|
|
.oe = 0, \
|
|
.pu = 1, \
|
|
.od = 0, \
|
|
}, \
|
|
}, \
|
|
}
|
|
|
|
static void stx7108_pio_dump_pad_config(const char *name, int port,
|
|
struct stm_pad_config *pad_config)
|
|
{
|
|
#ifdef DEBUG_RETIME_CONF
|
|
int i, gpios_num = pad_config->gpios_num;
|
|
|
|
pr_info("%s port=%d, gpios_num = %d\n", name, port, gpios_num);
|
|
|
|
pr_info("GPIO (retime\tclk1notclk0\tclknotdata\tdouble_edge\t"
|
|
"invertclk\tdelay_input)\n");
|
|
|
|
for (i = 0; i < gpios_num; i++) {
|
|
struct stm_pad_gpio *pad_gpio = &pad_config->gpios[i];
|
|
struct stx7108_pio_config *priv = pad_gpio->priv;
|
|
struct stx7108_pio_retime_config *retime = priv->retime;
|
|
|
|
pr_info("PIO%d[%d] %d\t\t%d\t\t%d\t%d\t\t%d\t\t%d\n",
|
|
stm_gpio_port(pad_gpio->gpio),
|
|
stm_gpio_pin(pad_gpio->gpio),
|
|
retime->retime, retime->clk1notclk0,
|
|
retime->clknotdata, retime->double_edge,
|
|
retime->invertclk, retime->delay_input);
|
|
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* MII Default Retiming Configuration */
|
|
static struct stx7108_pio_retime_config mii_retime_bypass = {
|
|
.retime = 0,
|
|
.clk1notclk0 = -1,
|
|
.clknotdata = 0,
|
|
.double_edge = -1,
|
|
.invertclk = -1,
|
|
.delay_input = -1,
|
|
|
|
};
|
|
|
|
static struct stx7108_pio_retime_config mii_retime_clock[] = {
|
|
[0] = {
|
|
.retime = -1,
|
|
.clk1notclk0 = 0,
|
|
.clknotdata = 1,
|
|
.double_edge = -1,
|
|
.invertclk = -1,
|
|
.delay_input = -1,
|
|
},
|
|
[1] = {
|
|
.retime = -1,
|
|
.clk1notclk0 = 1,
|
|
.clknotdata = 1,
|
|
.double_edge = -1,
|
|
.invertclk = -1,
|
|
.delay_input = -1,
|
|
}
|
|
};
|
|
|
|
static struct stx7108_pio_retime_config mii_retime_phy_clock = {
|
|
.retime = -1,
|
|
.clk1notclk0 = 0,
|
|
.clknotdata = 1,
|
|
.double_edge = -1,
|
|
.invertclk = -1,
|
|
.delay_input = -1,
|
|
};
|
|
|
|
static struct stx7108_pio_retime_config mii_retime_data[] = {
|
|
[0] = {
|
|
.retime = 1,
|
|
.clk1notclk0 = 0,
|
|
.clknotdata = 0,
|
|
.double_edge = -1,
|
|
.invertclk = -1,
|
|
.delay_input = -1,
|
|
},
|
|
[1] = {
|
|
.retime = 1,
|
|
.clk1notclk0 = 1,
|
|
.clknotdata = 0,
|
|
.double_edge = -1,
|
|
.invertclk = -1,
|
|
.delay_input = -1,
|
|
}
|
|
};
|
|
|
|
/* RMII Default Retiming Configuration */
|
|
static struct stx7108_pio_retime_config rmii_retime_data[] = {
|
|
[0] = {
|
|
.retime = 1,
|
|
.clk1notclk0 = 0,
|
|
.clknotdata = 0,
|
|
.double_edge = -1,
|
|
.invertclk = -1,
|
|
.delay_input = -1,
|
|
},
|
|
[1] = {
|
|
.retime = 1,
|
|
.clk1notclk0 = 0,
|
|
.clknotdata = 0,
|
|
.double_edge = -1,
|
|
.invertclk = -1,
|
|
.delay_input = -1,
|
|
}
|
|
};
|
|
|
|
|
|
/* GMII (GTX) Default Retiming Configuration */
|
|
static struct stx7108_pio_retime_config gmii_gtx_retime_clock = {
|
|
.retime = 1,
|
|
.clk1notclk0 = 1,
|
|
.clknotdata = 1,
|
|
.double_edge = 0,
|
|
.invertclk = -1,
|
|
.delay_input = 1,
|
|
};
|
|
|
|
/* RGMII (GTX) Default Retiming Configuration */
|
|
static struct stx7108_pio_retime_config rgmii_retime_bypass = {
|
|
.retime = 0,
|
|
.clk1notclk0 = -1,
|
|
.clknotdata = 0,
|
|
.double_edge = 1,
|
|
.invertclk = -1,
|
|
.delay_input = 0,
|
|
|
|
};
|
|
|
|
static struct stx7108_pio_retime_config rgmii_retime_clock[] = {
|
|
[0] = {
|
|
.retime = -1,
|
|
.clk1notclk0 = 0,
|
|
.clknotdata = 1,
|
|
.double_edge = 1,
|
|
.invertclk = -1,
|
|
.delay_input = 0,
|
|
},
|
|
[1] = {
|
|
.retime = -1,
|
|
.clk1notclk0 = 1,
|
|
.clknotdata = 1,
|
|
.double_edge = 1,
|
|
.invertclk = -1,
|
|
.delay_input = 0,
|
|
}
|
|
};
|
|
|
|
static struct stx7108_pio_retime_config rgmii_gtx_retime_clock = {
|
|
.retime = 1,
|
|
.clk1notclk0 = 1,
|
|
.clknotdata = 1,
|
|
.double_edge = 1,
|
|
.invertclk = -1,
|
|
.delay_input = 0,
|
|
};
|
|
|
|
static struct stx7108_pio_retime_config rgmii_retime_data[] = {
|
|
[0] = {
|
|
.retime = 1,
|
|
.clk1notclk0 = 0,
|
|
.clknotdata = 0,
|
|
.double_edge = 1,
|
|
.invertclk = -1,
|
|
.delay_input = 0,
|
|
},
|
|
[1] = {
|
|
.retime = 1,
|
|
.clk1notclk0 = 1,
|
|
.clknotdata = 0,
|
|
.double_edge = 1,
|
|
.invertclk = -1,
|
|
.delay_input = 0,
|
|
}
|
|
};
|
|
|
|
#define DATA_IN(_gmac, _port, _pin, _retiming) \
|
|
{ \
|
|
.gpio = stm_gpio(_port, _pin), \
|
|
.direction = stm_pad_gpio_direction_in, \
|
|
.function = _gmac + 1, \
|
|
.priv = &(struct stx7108_pio_config) { \
|
|
.retime = &_retiming[_gmac], \
|
|
}, \
|
|
}
|
|
|
|
#define DATA_OUT(_gmac, _port, _pin, _retiming) \
|
|
{ \
|
|
.gpio = stm_gpio(_port, _pin), \
|
|
.direction = stm_pad_gpio_direction_out, \
|
|
.function = _gmac + 1, \
|
|
.priv = &(struct stx7108_pio_config) { \
|
|
.retime = &_retiming[_gmac], \
|
|
}, \
|
|
}
|
|
|
|
#define CLOCK_IN(_gmac, _port, _pin, _retiming) \
|
|
{ \
|
|
.gpio = stm_gpio(_port, _pin), \
|
|
.direction = stm_pad_gpio_direction_in, \
|
|
.function = _gmac + 1, \
|
|
.priv = &(struct stx7108_pio_config) { \
|
|
.retime = &_retiming[_gmac], \
|
|
}, \
|
|
}
|
|
|
|
#define CLOCK_OUT(_gmac, _port, _pin, _retiming) \
|
|
{ \
|
|
.gpio = stm_gpio(_port, _pin), \
|
|
.direction = stm_pad_gpio_direction_out, \
|
|
.function = _gmac + 1, \
|
|
.priv = &(struct stx7108_pio_config) { \
|
|
.retime = &_retiming[_gmac], \
|
|
}, \
|
|
}
|
|
|
|
#define BYPASS_IN(_gmac, _port, _pin, _retiming) \
|
|
{ \
|
|
.gpio = stm_gpio(_port, _pin), \
|
|
.direction = stm_pad_gpio_direction_in, \
|
|
.function = _gmac + 1, \
|
|
.priv = &(struct stx7108_pio_config) { \
|
|
.retime = &_retiming, \
|
|
}, \
|
|
}
|
|
|
|
#define BYPASS_OUT(_gmac, _port, _pin, _retiming) \
|
|
{ \
|
|
.gpio = stm_gpio(_port, _pin), \
|
|
.direction = stm_pad_gpio_direction_out, \
|
|
.function = _gmac + 1, \
|
|
.priv = &(struct stx7108_pio_config) { \
|
|
.retime = &_retiming, \
|
|
}, \
|
|
}
|
|
|
|
#define PHY_CLOCK(_gmac, _port, _pin, _retiming) \
|
|
{ \
|
|
.gpio = stm_gpio(_port, _pin), \
|
|
.direction = stm_pad_gpio_direction_unknown, \
|
|
.name = "PHYCLK", \
|
|
.priv = &(struct stx7108_pio_config) { \
|
|
.retime = &_retiming, \
|
|
}, \
|
|
}
|
|
|
|
static struct stm_pad_config stx7108_ethernet_mii_pad_configs[] = {
|
|
[0] = {
|
|
.gpios_num = 20,
|
|
.gpios = (struct stm_pad_gpio []) {
|
|
DATA_OUT(0, 6, 0, mii_retime_data), /* TXD[0] */
|
|
DATA_OUT(0, 6, 1, mii_retime_data), /* TXD[1] */
|
|
DATA_OUT(0, 6, 2, mii_retime_data), /* TXD[2] */
|
|
DATA_OUT(0, 6, 3, mii_retime_data), /* TXD[3] */
|
|
DATA_OUT(0, 7, 0, mii_retime_data), /* TXER */
|
|
DATA_OUT(0, 7, 1, mii_retime_data), /* TXEN */
|
|
CLOCK_IN(0, 7, 2, mii_retime_clock), /* TXCLK */
|
|
BYPASS_IN(0, 7, 3, mii_retime_bypass), /* COL */
|
|
BYPASS_OUT(0, 7, 4, mii_retime_bypass), /* MDIO*/
|
|
CLOCK_OUT(0, 7, 5, mii_retime_clock), /* MDC */
|
|
BYPASS_IN(0, 7, 6, mii_retime_bypass), /* CRS */
|
|
BYPASS_IN(0, 7, 7, mii_retime_bypass), /* MDINT */
|
|
DATA_IN(0, 8, 0, mii_retime_data), /* RXD[0] */
|
|
DATA_IN(0, 8, 1, mii_retime_data), /* RXD[1] */
|
|
DATA_IN(0, 8, 2, mii_retime_data), /* RXD[2] */
|
|
DATA_IN(0, 8, 3, mii_retime_data), /* RXD[3] */
|
|
DATA_IN(0, 9, 0, mii_retime_data), /* RXDV */
|
|
DATA_IN(0, 9, 1, mii_retime_data), /* RX_ER */
|
|
CLOCK_IN(0, 9, 2, mii_retime_clock), /* RXCLK */
|
|
PHY_CLOCK(0, 9, 3, mii_retime_phy_clock),/* PHYCLK */
|
|
},
|
|
.sysconfs_num = 3,
|
|
.sysconfs = (struct stm_pad_sysconf []) {
|
|
/* EN_GMAC0 */
|
|
STM_PAD_SYS_CFG_BANK(2, 53, 0, 0, 1),
|
|
/* MIIx_PHY_SEL */
|
|
STM_PAD_SYS_CFG_BANK(2, 27, 2, 4, 0),
|
|
/* ENMIIx */
|
|
STM_PAD_SYS_CFG_BANK(2, 27, 5, 5, 1),
|
|
},
|
|
},
|
|
[1] = {
|
|
.gpios_num = 20,
|
|
.gpios = (struct stm_pad_gpio []) {
|
|
PHY_CLOCK(1, 15, 5, mii_retime_phy_clock),/* PHYCLK */
|
|
BYPASS_IN(1, 15, 6, mii_retime_bypass), /* MDINT */
|
|
DATA_OUT(1, 15, 7, mii_retime_data), /* TXEN */
|
|
DATA_OUT(1, 16, 0, mii_retime_data), /* TXD[0] */
|
|
DATA_OUT(1, 16, 1, mii_retime_data), /* TXD[1] */
|
|
DATA_OUT(1, 16, 2, mii_retime_data), /* TXD[2] */
|
|
DATA_OUT(1, 16, 3, mii_retime_data), /* TXD[3] */
|
|
CLOCK_IN(1, 17, 0, mii_retime_clock), /* TXCLK */
|
|
DATA_OUT(1, 17, 1, mii_retime_data), /* TXER */
|
|
BYPASS_IN(1, 17, 2, mii_retime_bypass), /* CRS */
|
|
BYPASS_IN(1, 17, 3, mii_retime_bypass), /* COL */
|
|
BYPASS_OUT(1, 17, 4, mii_retime_bypass),/* MDIO */
|
|
CLOCK_OUT(1, 17, 5, mii_retime_clock), /* MDC */
|
|
DATA_IN(1, 17, 6, mii_retime_data), /* RXDV */
|
|
DATA_IN(1, 17, 7, mii_retime_data), /* RX_ER */
|
|
DATA_IN(1, 18, 0, mii_retime_data), /* RXD[0] */
|
|
DATA_IN(1, 18, 1, mii_retime_data), /* RXD[1] */
|
|
DATA_IN(1, 18, 2, mii_retime_data), /* RXD[2] */
|
|
DATA_IN(1, 18, 3, mii_retime_data), /* RXD[3] */
|
|
CLOCK_IN(1, 19, 0, mii_retime_clock), /* RXCLK */
|
|
},
|
|
.sysconfs_num = 3,
|
|
.sysconfs = (struct stm_pad_sysconf []) {
|
|
/* EN_GMAC1 */
|
|
STM_PAD_SYS_CFG_BANK(4, 67, 0, 0, 1),
|
|
/* MIIx_PHY_SEL */
|
|
STM_PAD_SYS_CFG_BANK(4, 23, 2, 4, 0),
|
|
/* ENMIIx */
|
|
STM_PAD_SYS_CFG_BANK(4, 23, 5, 5, 1),
|
|
},
|
|
},
|
|
};
|
|
|
|
static struct stm_pad_config stx7108_ethernet_gmii_pad_configs[] = {
|
|
[0] = {
|
|
.gpios_num = 28,
|
|
.gpios = (struct stm_pad_gpio []) {
|
|
DATA_OUT(0, 6, 0, mii_retime_data), /* TXD[0] */
|
|
DATA_OUT(0, 6, 1, mii_retime_data), /* TXD[1] */
|
|
DATA_OUT(0, 6, 2, mii_retime_data), /* TXD[2] */
|
|
DATA_OUT(0, 6, 3, mii_retime_data), /* TXD[3] */
|
|
DATA_OUT(0, 6, 4, mii_retime_data), /* TXD[4] */
|
|
DATA_OUT(0, 6, 5, mii_retime_data), /* TXD[5] */
|
|
DATA_OUT(0, 6, 6, mii_retime_data), /* TXD[6] */
|
|
DATA_OUT(0, 6, 7, mii_retime_data), /* TXD[7] */
|
|
DATA_OUT(0, 7, 0, mii_retime_data), /* TXER */
|
|
DATA_OUT(0, 7, 1, mii_retime_data), /* TXEN */
|
|
CLOCK_IN(0, 7, 2, mii_retime_clock), /* TXCLK */
|
|
BYPASS_IN(0, 7, 3, mii_retime_bypass), /* COL */
|
|
BYPASS_OUT(0, 7, 4, mii_retime_bypass), /* MDIO */
|
|
CLOCK_OUT(0, 7, 5, mii_retime_clock), /* MDC */
|
|
BYPASS_IN(0, 7, 6, mii_retime_bypass), /* CRS */
|
|
BYPASS_IN(0, 7, 7, mii_retime_bypass), /* MDINT */
|
|
DATA_IN(0, 8, 0, mii_retime_data), /* RXD[0] */
|
|
DATA_IN(0, 8, 1, mii_retime_data), /* RXD[1] */
|
|
DATA_IN(0, 8, 2, mii_retime_data), /* RXD[2] */
|
|
DATA_IN(0, 8, 3, mii_retime_data), /* RXD[3] */
|
|
DATA_IN(0, 8, 4, mii_retime_data), /* RXD[4] */
|
|
DATA_IN(0, 8, 5, mii_retime_data), /* RXD[5] */
|
|
DATA_IN(0, 8, 6, mii_retime_data), /* RXD[6] */
|
|
DATA_IN(0, 8, 7, mii_retime_data), /* RXD[7] */
|
|
DATA_IN(0, 9, 0, mii_retime_data), /* RXDV */
|
|
DATA_IN(0, 9, 1, mii_retime_data), /* RX_ER */
|
|
CLOCK_IN(0, 9, 2, mii_retime_clock), /* RXCLK */
|
|
PHY_CLOCK(0, 9, 3, gmii_gtx_retime_clock),/* PHYCLK */
|
|
},
|
|
.sysconfs_num = 3,
|
|
.sysconfs = (struct stm_pad_sysconf []) {
|
|
/* EN_GMAC0 */
|
|
STM_PAD_SYS_CFG_BANK(2, 53, 0, 0, 1),
|
|
/* MIIx_PHY_SEL */
|
|
STM_PAD_SYS_CFG_BANK(2, 27, 2, 4, 0),
|
|
/* ENMIIx */
|
|
STM_PAD_SYS_CFG_BANK(2, 27, 5, 5, 1),
|
|
},
|
|
},
|
|
[1] = {
|
|
.gpios_num = 28,
|
|
.gpios = (struct stm_pad_gpio []) {
|
|
PHY_CLOCK(1, 15, 5, gmii_gtx_retime_clock),/* PHYCLK */
|
|
BYPASS_IN(1, 15, 6, mii_retime_bypass), /* MDINT */
|
|
DATA_OUT(1, 15, 7, mii_retime_data), /* TXEN */
|
|
DATA_OUT(1, 16, 0, mii_retime_data), /* TXD[0] */
|
|
DATA_OUT(1, 16, 1, mii_retime_data), /* TXD[1] */
|
|
DATA_OUT(1, 16, 2, mii_retime_data), /* TXD[2] */
|
|
DATA_OUT(1, 16, 3, mii_retime_data), /* TXD[3] */
|
|
DATA_OUT(1, 16, 4, mii_retime_data), /* TXD[4] */
|
|
DATA_OUT(1, 16, 5, mii_retime_data), /* TXD[5] */
|
|
DATA_OUT(1, 16, 6, mii_retime_data), /* TXD[6] */
|
|
DATA_OUT(1, 16, 7, mii_retime_data), /* TXD[7] */
|
|
CLOCK_IN(1, 17, 0, mii_retime_clock), /* TXCLK */
|
|
DATA_OUT(1, 17, 1, mii_retime_data), /* TXER */
|
|
BYPASS_IN(1, 17, 2, mii_retime_bypass), /* CRS */
|
|
BYPASS_IN(1, 17, 3, mii_retime_bypass), /* COL */
|
|
BYPASS_OUT(1, 17, 4, mii_retime_bypass),/* MDIO */
|
|
CLOCK_OUT(1, 17, 5, mii_retime_clock), /* MDC */
|
|
DATA_IN(1, 17, 6, mii_retime_data), /* RXDV */
|
|
DATA_IN(1, 17, 7, mii_retime_data), /* RX_ER */
|
|
DATA_IN(1, 18, 0, mii_retime_data), /* RXD[0] */
|
|
DATA_IN(1, 18, 1, mii_retime_data), /* RXD[1] */
|
|
DATA_IN(1, 18, 2, mii_retime_data), /* RXD[2] */
|
|
DATA_IN(1, 18, 3, mii_retime_data), /* RXD[3] */
|
|
DATA_IN(1, 18, 4, mii_retime_data), /* RXD[4] */
|
|
DATA_IN(1, 18, 5, mii_retime_data), /* RXD[5] */
|
|
DATA_IN(1, 18, 6, mii_retime_data), /* RXD[6] */
|
|
DATA_IN(1, 18, 7, mii_retime_data), /* RXD[7] */
|
|
CLOCK_IN(1, 19, 0, mii_retime_clock), /* RXCLK */
|
|
},
|
|
.sysconfs_num = 3,
|
|
.sysconfs = (struct stm_pad_sysconf []) {
|
|
/* EN_GMAC1 */
|
|
STM_PAD_SYS_CFG_BANK(4, 67, 0, 0, 1),
|
|
/* MIIx_PHY_SEL */
|
|
STM_PAD_SYS_CFG_BANK(4, 23, 2, 4, 0),
|
|
/* ENMIIx */
|
|
STM_PAD_SYS_CFG_BANK(4, 23, 5, 5, 1),
|
|
},
|
|
},
|
|
};
|
|
|
|
static struct stm_pad_config stx7108_ethernet_rgmii_pad_configs[] = {
|
|
[0] = {
|
|
.gpios_num = 18,
|
|
.gpios = (struct stm_pad_gpio []) {
|
|
DATA_OUT(0, 6, 0, rgmii_retime_data), /* TXD[0] */
|
|
DATA_OUT(0, 6, 1, rgmii_retime_data), /* TXD[1] */
|
|
DATA_OUT(0, 6, 2, rgmii_retime_data), /* TXD[2] */
|
|
DATA_OUT(0, 6, 3, rgmii_retime_data), /* TXD[3] */
|
|
DATA_OUT(0, 7, 1, rgmii_retime_data), /* TXEN */
|
|
CLOCK_IN(0, 7, 2, rgmii_retime_clock), /* TXCLK */
|
|
BYPASS_IN(0, 7, 3, rgmii_retime_bypass),/* COL */
|
|
BYPASS_OUT(0, 7, 4, rgmii_retime_bypass),/* MDIO */
|
|
CLOCK_OUT(0, 7, 5, rgmii_retime_clock), /* MDC */
|
|
BYPASS_IN(0, 7, 6, rgmii_retime_bypass),/* CRS */
|
|
BYPASS_IN(0, 7, 7, rgmii_retime_bypass),/* MDINT */
|
|
DATA_IN(0, 8, 0, rgmii_retime_data), /* RXD[0] */
|
|
DATA_IN(0, 8, 1, rgmii_retime_data), /* RXD[1] */
|
|
DATA_IN(0, 8, 2, rgmii_retime_data), /* RXD[2] */
|
|
DATA_IN(0, 8, 3, rgmii_retime_data), /* RXD[3] */
|
|
DATA_IN(0, 9, 0, rgmii_retime_data), /* RXDV */
|
|
CLOCK_IN(0, 9, 2, rgmii_retime_clock), /* RXCLK */
|
|
PHY_CLOCK(0, 9, 3, rgmii_gtx_retime_clock),/* PHYCLK */
|
|
},
|
|
.sysconfs_num = 3,
|
|
.sysconfs = (struct stm_pad_sysconf []) {
|
|
/* EN_GMAC0 */
|
|
STM_PAD_SYS_CFG_BANK(2, 53, 0, 0, 1),
|
|
/* MIIx_PHY_SEL */
|
|
STM_PAD_SYS_CFG_BANK(2, 27, 2, 4, 1),
|
|
/* ENMIIx */
|
|
STM_PAD_SYS_CFG_BANK(2, 27, 5, 5, 1),
|
|
},
|
|
},
|
|
[1] = {
|
|
.gpios_num = 18,
|
|
.gpios = (struct stm_pad_gpio []) {
|
|
PHY_CLOCK(1, 15, 5, rgmii_gtx_retime_clock),/* PHYCLK */
|
|
BYPASS_IN(1, 15, 6, rgmii_retime_bypass),/* MDINT */
|
|
DATA_OUT(1, 15, 7, rgmii_retime_data), /* TXEN */
|
|
DATA_OUT(1, 16, 0, rgmii_retime_data), /* TXD[0] */
|
|
DATA_OUT(1, 16, 1, rgmii_retime_data), /* TXD[1] */
|
|
DATA_OUT(1, 16, 2, rgmii_retime_data), /* TXD[2] */
|
|
DATA_OUT(1, 16, 3, rgmii_retime_data), /* TXD[3] */
|
|
CLOCK_IN(1, 17, 0, rgmii_retime_clock), /* TXCLK */
|
|
BYPASS_IN(1, 17, 2, rgmii_retime_bypass),/* CRS */
|
|
BYPASS_IN(1, 17, 3, rgmii_retime_bypass),/* COL */
|
|
BYPASS_OUT(1, 17, 4, rgmii_retime_bypass),/* MDIO */
|
|
CLOCK_OUT(1, 17, 5, rgmii_retime_clock),/* MDC */
|
|
DATA_IN(1, 17, 6, rgmii_retime_data), /* RXDV */
|
|
DATA_IN(1, 18, 0, rgmii_retime_data), /* RXD[0] */
|
|
DATA_IN(1, 18, 1, rgmii_retime_data), /* RXD[1] */
|
|
DATA_IN(1, 18, 2, rgmii_retime_data), /* RXD[2] */
|
|
DATA_IN(1, 18, 3, rgmii_retime_data), /* RXD[3] */
|
|
CLOCK_IN(1, 19, 0, rgmii_retime_clock), /* RXCLK */
|
|
},
|
|
.sysconfs_num = 3,
|
|
.sysconfs = (struct stm_pad_sysconf []) {
|
|
/* EN_GMAC1 */
|
|
STM_PAD_SYS_CFG_BANK(4, 67, 0, 0, 1),
|
|
/* MIIx_PHY_SEL */
|
|
STM_PAD_SYS_CFG_BANK(4, 23, 2, 4, 1),
|
|
/* ENMIIx */
|
|
STM_PAD_SYS_CFG_BANK(4, 23, 5, 5, 1),
|
|
},
|
|
},
|
|
};
|
|
#define RMII_PHY_CLOCK(_gmac, _port, _pin, _retiming) \
|
|
{ \
|
|
.gpio = stm_gpio(_port, _pin), \
|
|
.direction = stm_pad_gpio_direction_in, \
|
|
.function = 2, \
|
|
.name = "PHYCLK", \
|
|
.priv = &(struct stx7108_pio_config) { \
|
|
.retime = &_retiming, \
|
|
}, \
|
|
}
|
|
|
|
static struct stx7108_pio_retime_config rmii_txd_retime_bypass = {
|
|
.retime = 1,
|
|
.clk1notclk0 = 1,
|
|
.clknotdata = 0,
|
|
.double_edge = 0,
|
|
.invertclk = 0,
|
|
.delay_input = 0,
|
|
};
|
|
|
|
static struct stx7108_pio_retime_config rmii_mdio_retime_bypass = {
|
|
.retime = 0,
|
|
.clk1notclk0 = -1,
|
|
.clknotdata = 0,
|
|
.double_edge = -1,
|
|
.invertclk = -1,
|
|
.delay_input = 3,
|
|
};
|
|
static struct stx7108_pio_retime_config rmii_mdc_retime_bypass = {
|
|
.retime = 1,
|
|
.clk1notclk0 = 0,
|
|
.clknotdata = 1,
|
|
.double_edge = -1,
|
|
.invertclk = 0,
|
|
.delay_input = 0,
|
|
};
|
|
|
|
static struct stx7108_pio_retime_config rmii_mdint_retime_bypass = {
|
|
.retime = 0,
|
|
.clk1notclk0 = -1,
|
|
.clknotdata = 0,
|
|
.double_edge = -1,
|
|
.invertclk = -1,
|
|
.delay_input = 0,
|
|
};
|
|
|
|
static struct stx7108_pio_retime_config rmii_rxd_retime_bypass = {
|
|
.retime = 1,
|
|
.clk1notclk0 = 1,
|
|
.clknotdata = 0,
|
|
.double_edge = 0,
|
|
.invertclk = 0,
|
|
.delay_input = 2,
|
|
};
|
|
|
|
static struct stx7108_pio_retime_config rmii_retime_phy_clock = {
|
|
.retime = 1,
|
|
.clk1notclk0 = 0,
|
|
.clknotdata = 1,
|
|
.double_edge = -1,
|
|
.invertclk = 0,
|
|
.delay_input = 0,
|
|
};
|
|
|
|
|
|
static struct stm_pad_config stx7108_ethernet_rmii_pad_configs[] = {
|
|
[0] = {
|
|
.gpios_num = 12,
|
|
.gpios = (struct stm_pad_gpio []) {
|
|
BYPASS_OUT(0, 6, 0, rmii_txd_retime_bypass),/* TXD[0] */
|
|
BYPASS_OUT(0, 6, 1, rmii_txd_retime_bypass),/* TXD[1] */
|
|
BYPASS_OUT(0, 7, 0, rmii_txd_retime_bypass),/* TXER */
|
|
BYPASS_OUT(0, 7, 1, rmii_txd_retime_bypass),/* TXEN */
|
|
BYPASS_IN(0, 7, 7, rmii_mdint_retime_bypass),/* MDINT */
|
|
/* MDIO with internal pull-up */
|
|
ETH_MDIO_BIDIR(0, 7, 4, rmii_mdio_retime_bypass),
|
|
BYPASS_OUT(0, 7, 5, rmii_mdc_retime_bypass),/* MDC */
|
|
BYPASS_IN(0, 8, 0, rmii_rxd_retime_bypass),/* RXD.0 */
|
|
BYPASS_IN(0, 8, 1, rmii_rxd_retime_bypass),/* RXD.1 */
|
|
BYPASS_IN(0, 9, 0, rmii_rxd_retime_bypass),/* RXDV */
|
|
BYPASS_IN(0, 9, 1, rmii_rxd_retime_bypass),/* RX_ER */
|
|
PHY_CLOCK(0, 9, 3, rmii_retime_phy_clock),/* PHYCLK */
|
|
},
|
|
.sysconfs_num = 3,
|
|
.sysconfs = (struct stm_pad_sysconf []) {
|
|
/* EN_GMAC0 */
|
|
STM_PAD_SYS_CFG_BANK(2, 53, 0, 0, 1),
|
|
/* MIIx_PHY_SEL */
|
|
STM_PAD_SYS_CFG_BANK(2, 27, 2, 4, 4),
|
|
/* ENMIIx */
|
|
STM_PAD_SYS_CFG_BANK(2, 27, 5, 5, 1),
|
|
},
|
|
},
|
|
[1] = {
|
|
.gpios_num = 12,
|
|
.gpios = (struct stm_pad_gpio []) {
|
|
PHY_CLOCK(1, 15, 5, mii_retime_phy_clock),/* PHYCLK */
|
|
BYPASS_IN(1, 15, 6, mii_retime_bypass), /* MDINT */
|
|
DATA_OUT(1, 15, 7, rmii_retime_data), /* TXEN */
|
|
DATA_OUT(1, 16, 0, rmii_retime_data), /* TXD[0] */
|
|
DATA_OUT(1, 16, 1, rmii_retime_data), /* TXD[1] */
|
|
DATA_OUT(1, 17, 1, rmii_retime_data), /* TXER */
|
|
BYPASS_OUT(1, 17, 4, mii_retime_bypass),/* MDIO */
|
|
CLOCK_OUT(1, 17, 5, mii_retime_clock), /* MDC */
|
|
DATA_IN(1, 17, 6, rmii_retime_data), /* RXDV */
|
|
DATA_IN(1, 17, 7, rmii_retime_data), /* RX_ER */
|
|
DATA_IN(1, 18, 0, rmii_retime_data), /* RXD[0] */
|
|
DATA_IN(1, 18, 1, rmii_retime_data), /* RXD[1] */
|
|
},
|
|
.sysconfs_num = 3,
|
|
.sysconfs = (struct stm_pad_sysconf []) {
|
|
/* EN_GMAC1 */
|
|
STM_PAD_SYS_CFG_BANK(4, 67, 0, 0, 1),
|
|
/* MIIx_PHY_SEL */
|
|
STM_PAD_SYS_CFG_BANK(4, 23, 2, 4, 4),
|
|
/* ENMIIx */
|
|
STM_PAD_SYS_CFG_BANK(4, 23, 5, 5, 1),
|
|
},
|
|
},
|
|
};
|
|
|
|
static struct stm_pad_config stx7108_ethernet_reverse_mii_pad_configs[] = {
|
|
[0] = {
|
|
.gpios_num = 20,
|
|
.gpios = (struct stm_pad_gpio []) {
|
|
DATA_OUT(0, 6, 0, mii_retime_data), /* TXD[0] */
|
|
DATA_OUT(0, 6, 1, mii_retime_data), /* TXD[1] */
|
|
DATA_OUT(0, 6, 2, mii_retime_data), /* TXD[2] */
|
|
DATA_OUT(0, 6, 3, mii_retime_data), /* TXD[3] */
|
|
DATA_OUT(0, 7, 0, mii_retime_data), /* TXER */
|
|
DATA_OUT(0, 7, 1, mii_retime_data), /* TXEN */
|
|
CLOCK_IN(0, 7, 2, mii_retime_clock), /* TXCLK */
|
|
BYPASS_OUT(0, 7, 3, mii_retime_bypass), /* COL */
|
|
BYPASS_OUT(0, 7, 4, mii_retime_bypass), /* MDIO*/
|
|
CLOCK_IN(0, 7, 5, mii_retime_clock), /* MDC */
|
|
BYPASS_OUT(0, 7, 6, mii_retime_bypass), /* CRS */
|
|
BYPASS_IN(0, 7, 7, mii_retime_bypass), /* MDINT */
|
|
DATA_IN(0, 8, 0, mii_retime_data), /* RXD[0] */
|
|
DATA_IN(0, 8, 1, mii_retime_data), /* RXD[1] */
|
|
DATA_IN(0, 8, 2, mii_retime_data), /* RXD[2] */
|
|
DATA_IN(0, 8, 3, mii_retime_data), /* RXD[3] */
|
|
DATA_IN(0, 9, 0, mii_retime_data), /* RXDV */
|
|
DATA_IN(0, 9, 1, mii_retime_data), /* RX_ER */
|
|
CLOCK_IN(0, 9, 2, mii_retime_clock), /* RXCLK */
|
|
PHY_CLOCK(0, 9, 3, mii_retime_phy_clock),/* PHYCLK */
|
|
},
|
|
.sysconfs_num = 3,
|
|
.sysconfs = (struct stm_pad_sysconf []) {
|
|
/* EN_GMAC0 */
|
|
STM_PAD_SYS_CFG_BANK(2, 53, 0, 0, 1),
|
|
/* MIIx_PHY_SEL */
|
|
STM_PAD_SYS_CFG_BANK(2, 27, 2, 4, 0),
|
|
/* ENMIIx */
|
|
STM_PAD_SYS_CFG_BANK(2, 27, 5, 5, 0),
|
|
},
|
|
},
|
|
[1] = {
|
|
.gpios_num = 20,
|
|
.gpios = (struct stm_pad_gpio []) {
|
|
PHY_CLOCK(1, 15, 5, mii_retime_phy_clock),/* PHYCLK */
|
|
BYPASS_IN(1, 15, 6, mii_retime_bypass), /* MDINT */
|
|
DATA_OUT(1, 15, 7, mii_retime_data), /* TXEN */
|
|
DATA_OUT(1, 16, 0, mii_retime_data), /* TXD[0] */
|
|
DATA_OUT(1, 16, 1, mii_retime_data), /* TXD[1] */
|
|
DATA_OUT(1, 16, 2, mii_retime_data), /* TXD[2] */
|
|
DATA_OUT(1, 16, 3, mii_retime_data), /* TXD[3] */
|
|
CLOCK_IN(1, 17, 0, mii_retime_clock), /* TXCLK */
|
|
DATA_OUT(1, 17, 1, mii_retime_data), /* TXER */
|
|
BYPASS_OUT(1, 17, 2, mii_retime_bypass),/* CRS */
|
|
BYPASS_OUT(1, 17, 3, mii_retime_bypass),/* COL */
|
|
BYPASS_OUT(1, 17, 4, mii_retime_bypass),/* MDIO */
|
|
CLOCK_IN(1, 17, 5, mii_retime_clock), /* MDC */
|
|
DATA_IN(1, 17, 6, mii_retime_data), /* RXDV */
|
|
DATA_IN(1, 17, 7, mii_retime_data), /* RX_ER */
|
|
DATA_IN(1, 18, 0, mii_retime_data), /* RXD[0] */
|
|
DATA_IN(1, 18, 1, mii_retime_data), /* RXD[1] */
|
|
DATA_IN(1, 18, 2, mii_retime_data), /* RXD[2] */
|
|
DATA_IN(1, 18, 3, mii_retime_data), /* RXD[3] */
|
|
CLOCK_IN(1, 19, 0, mii_retime_clock), /* RXCLK */
|
|
},
|
|
.sysconfs_num = 3,
|
|
.sysconfs = (struct stm_pad_sysconf []) {
|
|
/* EN_GMAC1 */
|
|
STM_PAD_SYS_CFG_BANK(4, 67, 0, 0, 1),
|
|
/* MIIx_PHY_SEL */
|
|
STM_PAD_SYS_CFG_BANK(4, 23, 2, 4, 0),
|
|
/* ENMIIx */
|
|
STM_PAD_SYS_CFG_BANK(4, 23, 5, 5, 1),
|
|
},
|
|
},
|
|
};
|
|
|
|
static void stx7108_ethernet_rmii_speed(void *bsp_priv, unsigned int speed)
|
|
{
|
|
struct sysconf_field *mac_speed_sel = bsp_priv;
|
|
|
|
sysconf_write(mac_speed_sel, (speed == SPEED_100) ? 1 : 0);
|
|
}
|
|
|
|
static void stx7108_ethernet_gtx_speed(void *priv, unsigned int speed)
|
|
{
|
|
void (*txclk_select)(int txclk_250_not_25_mhz) = priv;
|
|
|
|
if (txclk_select)
|
|
txclk_select(speed == SPEED_1000);
|
|
}
|
|
|
|
static struct plat_stmmacenet_data stx7108_ethernet_platform_data[] = {
|
|
{
|
|
.pbl = 32,
|
|
.has_gmac = 1,
|
|
.enh_desc = 1,
|
|
.tx_coe = 1,
|
|
.bugged_jumbo =1,
|
|
.pmt = 1,
|
|
.init = &stmmac_claim_resource,
|
|
}, {
|
|
.pbl = 32,
|
|
.has_gmac = 1,
|
|
.enh_desc = 1,
|
|
.tx_coe = 1,
|
|
.bugged_jumbo =1,
|
|
.pmt = 1,
|
|
.init = &stmmac_claim_resource,
|
|
}
|
|
};
|
|
|
|
static struct platform_device stx7108_ethernet_devices[] = {
|
|
{
|
|
.name = "stmmaceth",
|
|
.id = 0,
|
|
.num_resources = 2,
|
|
.resource = (struct resource[]) {
|
|
STM_PLAT_RESOURCE_MEM(0xfda88000, 0x8000),
|
|
STM_PLAT_RESOURCE_IRQ_NAMED("macirq", ILC_IRQ(21), -1),
|
|
},
|
|
.dev.platform_data = &stx7108_ethernet_platform_data[0],
|
|
}, {
|
|
.name = "stmmaceth",
|
|
.id = 1,
|
|
.num_resources = 2,
|
|
.resource = (struct resource[]) {
|
|
STM_PLAT_RESOURCE_MEM(0xfe730000, 0x8000),
|
|
STM_PLAT_RESOURCE_IRQ_NAMED("macirq", ILC_IRQ(23), -1),
|
|
},
|
|
.dev.platform_data = &stx7108_ethernet_platform_data[1],
|
|
}
|
|
};
|
|
|
|
#define GMAC_AHB_CONFIG 0x7000
|
|
static void stx7108_ethernet_bus_setup(void __iomem *ioaddr)
|
|
{
|
|
/* Configure the bridge to generate more efficient STBus traffic.
|
|
*
|
|
* Cut Version | Ethernet AD_CONFIG[21:0]
|
|
* ---------------------------------------
|
|
* 1.1 | 0x00264006
|
|
* 2.0 | 0x00264207
|
|
*/
|
|
if (boot_cpu_data.cut_major == 1)
|
|
writel(0x00264006, ioaddr + GMAC_AHB_CONFIG);
|
|
else if (boot_cpu_data.cut_major == 2)
|
|
writel(0x00264207, ioaddr + GMAC_AHB_CONFIG);
|
|
}
|
|
|
|
void __init stx7108_configure_ethernet(int port,
|
|
struct stx7108_ethernet_config *config)
|
|
{
|
|
static int configured[ARRAY_SIZE(stx7108_ethernet_devices)];
|
|
struct stx7108_ethernet_config default_config;
|
|
struct plat_stmmacenet_data *plat_data;
|
|
struct stm_pad_config *pad_config;
|
|
int interface;
|
|
|
|
BUG_ON(port < 0 || port >= ARRAY_SIZE(stx7108_ethernet_devices));
|
|
BUG_ON(configured[port]++);
|
|
|
|
if (!config)
|
|
config = &default_config;
|
|
|
|
plat_data = &stx7108_ethernet_platform_data[port];
|
|
|
|
switch (config->mode) {
|
|
case stx7108_ethernet_mode_mii:
|
|
pad_config = &stx7108_ethernet_mii_pad_configs[port];
|
|
if (config->ext_clk)
|
|
stm_pad_set_pio_ignored(pad_config, "PHYCLK");
|
|
else
|
|
stm_pad_set_pio_out(pad_config, "PHYCLK", 1 + port);
|
|
interface = PHY_INTERFACE_MODE_MII;
|
|
break;
|
|
case stx7108_ethernet_mode_gmii:
|
|
pad_config = &stx7108_ethernet_gmii_pad_configs[port];
|
|
stm_pad_set_pio_ignored(pad_config, "PHYCLK");
|
|
interface = PHY_INTERFACE_MODE_GMII;
|
|
break;
|
|
case stx7108_ethernet_mode_gmii_gtx:
|
|
pad_config = &stx7108_ethernet_gmii_pad_configs[port];
|
|
stm_pad_set_pio_out(pad_config, "PHYCLK", 1 + port);
|
|
plat_data->fix_mac_speed = stx7108_ethernet_gtx_speed;
|
|
plat_data->bsp_priv = config->txclk_select;
|
|
interface = PHY_INTERFACE_MODE_GMII;
|
|
break;
|
|
case stx7108_ethernet_mode_rgmii_gtx:
|
|
/* This mode is similar to GMII (GTX) except the data
|
|
* buses are reduced down to 4 bits and the 2 error
|
|
* signals are removed. The data rate is maintained by
|
|
* using both edges of the clock. This also explains
|
|
* the different retiming configuration for this mode.
|
|
*/
|
|
pad_config = &stx7108_ethernet_rgmii_pad_configs[port];
|
|
stm_pad_set_pio_out(pad_config, "PHYCLK", 1 + port);
|
|
plat_data->fix_mac_speed = stx7108_ethernet_gtx_speed;
|
|
plat_data->bsp_priv = config->txclk_select;
|
|
interface = PHY_INTERFACE_MODE_RGMII;
|
|
break;
|
|
case stx7108_ethernet_mode_rmii: /* GMAC1 only tested */
|
|
pad_config = &stx7108_ethernet_rmii_pad_configs[port];
|
|
if (config->ext_clk)
|
|
stm_pad_set_pio_in(pad_config, "PHYCLK", 2 + port);
|
|
else {
|
|
unsigned long phy_clk_rate;
|
|
struct clk *phy_clk = clk_get(NULL, "CLKA_ETH_PHY_1");
|
|
|
|
BUG_ON(!phy_clk);
|
|
stm_pad_set_pio_out(pad_config, "PHYCLK", 1 + port);
|
|
|
|
phy_clk_rate = 50000000;
|
|
clk_set_rate(phy_clk, phy_clk_rate);
|
|
}
|
|
plat_data->fix_mac_speed = stx7108_ethernet_rmii_speed;
|
|
/* MIIx_MAC_SPEED_SEL */
|
|
if (port == 0)
|
|
plat_data->bsp_priv = sysconf_claim(SYS_CFG_BANK2,
|
|
27, 1, 1, "stmmac");
|
|
else
|
|
plat_data->bsp_priv = sysconf_claim(SYS_CFG_BANK4,
|
|
23, 1, 1, "stmmac");
|
|
interface = PHY_INTERFACE_MODE_RMII;
|
|
break;
|
|
case stx7108_ethernet_mode_reverse_mii:
|
|
pad_config = &stx7108_ethernet_reverse_mii_pad_configs[port];
|
|
if (config->ext_clk)
|
|
stm_pad_set_pio_ignored(pad_config, "PHYCLK");
|
|
else
|
|
stm_pad_set_pio_out(pad_config, "PHYCLK", 1 + port);
|
|
interface = PHY_INTERFACE_MODE_MII;
|
|
break;
|
|
default:
|
|
BUG();
|
|
return;
|
|
}
|
|
|
|
stx7108_ethernet_platform_data[port].bus_setup =
|
|
stx7108_ethernet_bus_setup;
|
|
|
|
plat_data->custom_cfg = (void *) pad_config;
|
|
plat_data->interface = interface;
|
|
plat_data->bus_id = config->phy_bus;
|
|
plat_data->phy_addr = config->phy_addr;
|
|
plat_data->mdio_bus_data = config->mdio_bus_data;
|
|
|
|
stx7108_pio_dump_pad_config(stx7108_ethernet_devices[port].name,
|
|
port, pad_config);
|
|
|
|
platform_device_register(&stx7108_ethernet_devices[port]);
|
|
}
|
|
|
|
|
|
|
|
/* USB resources ---------------------------------------------------------- */
|
|
|
|
static u64 stx7108_usb_dma_mask = DMA_BIT_MASK(32);
|
|
|
|
#define USB_HOST_PWR "USB_HOST_PWR"
|
|
#define USB_PHY_INDCSHIFT "USB_PHY_INDCSHIFT"
|
|
#define USB_PHY_INEDGECTL "USB_PHY_INEDGECTL"
|
|
#define USB_PWR_ACK "USB_PWR_ACK"
|
|
|
|
static int stx7108_usb_init(struct stm_device_state *device_state)
|
|
{
|
|
/* USB edge rise and DC shift - STLinux Bugzilla 10991 */
|
|
stm_device_sysconf_write(device_state, USB_PHY_INDCSHIFT, 0);
|
|
stm_device_sysconf_write(device_state, USB_PHY_INEDGECTL, 1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void stx7108_usb_power(struct stm_device_state *device_state,
|
|
enum stm_device_power_state power)
|
|
{
|
|
int i;
|
|
int value = (power == stm_device_power_on) ? 0 : 1;
|
|
|
|
stm_device_sysconf_write(device_state, USB_HOST_PWR, value);
|
|
|
|
for (i = 5; i; --i) {
|
|
if (stm_device_sysconf_read(device_state, USB_PWR_ACK)
|
|
== value)
|
|
break;
|
|
mdelay(10);
|
|
}
|
|
}
|
|
|
|
static struct stm_plat_usb_data stx7108_usb_platform_data[] = {
|
|
[0] = {
|
|
.flags = STM_PLAT_USB_FLAGS_STRAP_8BIT |
|
|
STM_PLAT_USB_FLAGS_STBUS_CONFIG_THRESHOLD128,
|
|
.device_config = &(struct stm_device_config){
|
|
.init = stx7108_usb_init,
|
|
.power = stx7108_usb_power,
|
|
.sysconfs_num = 4,
|
|
.sysconfs = (struct stm_device_sysconf []) {
|
|
STM_DEVICE_SYS_CFG_BANK(4, 46, 0, 0,
|
|
USB_HOST_PWR),
|
|
STM_DEVICE_SYS_CFG_BANK(4, 44, 0, 0,
|
|
USB_PHY_INDCSHIFT),
|
|
STM_DEVICE_SYS_CFG_BANK(4, 44, 3, 3,
|
|
USB_PHY_INEDGECTL),
|
|
STM_DEVICE_SYS_STA_BANK(4, 2, 0, 0,
|
|
USB_PWR_ACK),
|
|
},
|
|
.pad_config = &(struct stm_pad_config) {
|
|
.gpios_num = 2,
|
|
.gpios = (struct stm_pad_gpio []) {
|
|
/* Overcurrent detection */
|
|
STM_PAD_PIO_IN(23, 6, 1),
|
|
/* USB power enable */
|
|
STM_PAD_PIO_OUT(23, 7, 1),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
[1] = {
|
|
.flags = STM_PLAT_USB_FLAGS_STRAP_8BIT |
|
|
STM_PLAT_USB_FLAGS_STBUS_CONFIG_THRESHOLD128,
|
|
.device_config = &(struct stm_device_config){
|
|
.init = stx7108_usb_init,
|
|
.power = stx7108_usb_power,
|
|
.sysconfs_num = 4,
|
|
.sysconfs = (struct stm_device_sysconf []) {
|
|
STM_DEVICE_SYS_CFG_BANK(4, 46, 1, 1,
|
|
USB_HOST_PWR),
|
|
STM_DEVICE_SYS_CFG_BANK(4, 44, 1, 1,
|
|
USB_PHY_INDCSHIFT),
|
|
STM_DEVICE_SYS_CFG_BANK(4, 44, 4, 4,
|
|
USB_PHY_INEDGECTL),
|
|
STM_DEVICE_SYS_STA_BANK(4, 2, 1, 1,
|
|
USB_PWR_ACK),
|
|
},
|
|
.pad_config = &(struct stm_pad_config) {
|
|
.gpios_num = 2,
|
|
.gpios = (struct stm_pad_gpio []) {
|
|
/* Overcurrent detection */
|
|
STM_PAD_PIO_IN(24, 0, 1),
|
|
/* USB power enable */
|
|
STM_PAD_PIO_OUT(24, 1, 1),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
[2] = {
|
|
.flags = STM_PLAT_USB_FLAGS_STRAP_8BIT |
|
|
STM_PLAT_USB_FLAGS_STBUS_CONFIG_THRESHOLD128,
|
|
.device_config = &(struct stm_device_config){
|
|
.init = stx7108_usb_init,
|
|
.power = stx7108_usb_power,
|
|
.sysconfs_num = 4,
|
|
.sysconfs = (struct stm_device_sysconf []) {
|
|
STM_DEVICE_SYS_CFG_BANK(4, 46, 2, 2,
|
|
USB_HOST_PWR),
|
|
STM_DEVICE_SYS_CFG_BANK(4, 44, 2, 2,
|
|
USB_PHY_INDCSHIFT),
|
|
STM_DEVICE_SYS_CFG_BANK(4, 44, 5, 5,
|
|
USB_PHY_INEDGECTL),
|
|
STM_DEVICE_SYS_STA_BANK(4, 2, 2, 2,
|
|
USB_PWR_ACK),
|
|
},
|
|
.pad_config = &(struct stm_pad_config) {
|
|
.gpios_num = 2,
|
|
.gpios = (struct stm_pad_gpio []) {
|
|
/* Overcurrent detection */
|
|
STM_PAD_PIO_IN(24, 2, 1),
|
|
/* USB power enable */
|
|
STM_PAD_PIO_OUT(24, 3, 1),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
};
|
|
|
|
static struct platform_device stx7108_usb_devices[] = {
|
|
[0] = {
|
|
.name = "stm-usb",
|
|
.id = 0,
|
|
.dev = {
|
|
.dma_mask = &stx7108_usb_dma_mask,
|
|
.coherent_dma_mask = DMA_BIT_MASK(32),
|
|
.platform_data = &stx7108_usb_platform_data[0],
|
|
},
|
|
.num_resources = 6,
|
|
.resource = (struct resource[]) {
|
|
STM_PLAT_RESOURCE_MEM_NAMED("wrapper",
|
|
0xfe000000, 0x100),
|
|
STM_PLAT_RESOURCE_MEM_NAMED("ohci",
|
|
0xfe0ffc00, 0x100),
|
|
STM_PLAT_RESOURCE_MEM_NAMED("ehci",
|
|
0xfe0ffe00, 0x100),
|
|
STM_PLAT_RESOURCE_MEM_NAMED("protocol",
|
|
0xfe0fff00, 0x100),
|
|
STM_PLAT_RESOURCE_IRQ_NAMED("ehci", ILC_IRQ(59), -1),
|
|
STM_PLAT_RESOURCE_IRQ_NAMED("ohci", ILC_IRQ(62), -1),
|
|
},
|
|
},
|
|
[1] = {
|
|
.name = "stm-usb",
|
|
.id = 1,
|
|
.dev = {
|
|
.dma_mask = &stx7108_usb_dma_mask,
|
|
.coherent_dma_mask = DMA_BIT_MASK(32),
|
|
.platform_data = &stx7108_usb_platform_data[1],
|
|
},
|
|
.num_resources = 6,
|
|
.resource = (struct resource[]) {
|
|
STM_PLAT_RESOURCE_MEM_NAMED("wrapper",
|
|
0xfe100000, 0x100),
|
|
STM_PLAT_RESOURCE_MEM_NAMED("ohci",
|
|
0xfe1ffc00, 0x100),
|
|
STM_PLAT_RESOURCE_MEM_NAMED("ehci",
|
|
0xfe1ffe00, 0x100),
|
|
STM_PLAT_RESOURCE_MEM_NAMED("protocol",
|
|
0xfe1fff00, 0x100),
|
|
STM_PLAT_RESOURCE_IRQ_NAMED("ehci", ILC_IRQ(60), -1),
|
|
STM_PLAT_RESOURCE_IRQ_NAMED("ohci", ILC_IRQ(63), -1),
|
|
},
|
|
},
|
|
[2] = {
|
|
.name = "stm-usb",
|
|
.id = 2,
|
|
.dev = {
|
|
.dma_mask = &stx7108_usb_dma_mask,
|
|
.coherent_dma_mask = DMA_BIT_MASK(32),
|
|
.platform_data = &stx7108_usb_platform_data[2],
|
|
},
|
|
.num_resources = 6,
|
|
.resource = (struct resource[]) {
|
|
STM_PLAT_RESOURCE_MEM_NAMED("wrapper",
|
|
0xfe200000, 0x100),
|
|
STM_PLAT_RESOURCE_MEM_NAMED("ohci",
|
|
0xfe2ffc00, 0x100),
|
|
STM_PLAT_RESOURCE_MEM_NAMED("ehci",
|
|
0xfe2ffe00, 0x100),
|
|
STM_PLAT_RESOURCE_MEM_NAMED("protocol",
|
|
0xfe2fff00, 0x100),
|
|
STM_PLAT_RESOURCE_IRQ_NAMED("ehci", ILC_IRQ(61), -1),
|
|
STM_PLAT_RESOURCE_IRQ_NAMED("ohci", ILC_IRQ(64), -1),
|
|
},
|
|
},
|
|
};
|
|
|
|
void __init stx7108_configure_usb(int port)
|
|
{
|
|
static int osc_initialized;
|
|
static int configured[ARRAY_SIZE(stx7108_usb_devices)];
|
|
struct sysconf_field *sc;
|
|
|
|
BUG_ON(port < 0 || port >= ARRAY_SIZE(stx7108_usb_devices));
|
|
|
|
BUG_ON(configured[port]++);
|
|
|
|
if (!osc_initialized++) {
|
|
/* USB2TRIPPHY_OSCIOK */
|
|
sc = sysconf_claim(SYS_CFG_BANK4, 44, 6, 6, "USB");
|
|
sysconf_write(sc, 1);
|
|
}
|
|
|
|
platform_device_register(&stx7108_usb_devices[port]);
|
|
}
|
|
|
|
|
|
|
|
/* MiPHY resources -------------------------------------------------------- */
|
|
|
|
#define MAX_PORTS 2
|
|
|
|
/*
|
|
* NOTE: In 7108 SYSCONF BANK0 the register numbering jumps from 8 to
|
|
* 12, which breaks the sysconf drivers. So when accessing registers
|
|
* 12, 13, 14 we need to manually substract 3, as generic sysconf
|
|
* infrastructure does not takecare of such deviations.
|
|
*/
|
|
#define BANK0_REG(reg) (reg - 3)
|
|
|
|
#define PCIE_BASE 0xfe780000
|
|
#define PCIE_UPORT_BASE (PCIE_BASE + 0x4000)
|
|
#define PCIE_UPORT_REG_SIZE (0xFF)
|
|
|
|
static __initdata int stx7108_using_uport;
|
|
static enum miphy_mode stx7108_miphy_modes[2];
|
|
static struct sysconf_field *sc_pcie_mp_select;
|
|
static struct sysconf_field *sc_miphy_reset[MAX_PORTS];
|
|
|
|
static void stx7108_pcie_mp_select(int port)
|
|
{
|
|
BUG_ON(port < 0 || port > 1);
|
|
sysconf_write(sc_pcie_mp_select, port);
|
|
}
|
|
|
|
struct stm_plat_pcie_mp_data stx7108_pcie_mp_platform_data = {
|
|
.miphy_first = 0,
|
|
.miphy_count = 2,
|
|
.miphy_modes = stx7108_miphy_modes,
|
|
.mp_select = stx7108_pcie_mp_select,
|
|
};
|
|
|
|
static struct platform_device stx7108_pcie_mp_device = {
|
|
.name = "pcie-mp",
|
|
.id = 0,
|
|
.num_resources = 1,
|
|
.resource = (struct resource[]) {
|
|
[0] = {
|
|
.start = PCIE_UPORT_BASE,
|
|
.end = PCIE_UPORT_BASE + PCIE_UPORT_REG_SIZE,
|
|
.flags = IORESOURCE_MEM,
|
|
},
|
|
},
|
|
.dev = {
|
|
.platform_data = &stx7108_pcie_mp_platform_data,
|
|
}
|
|
};
|
|
|
|
/* TAP private data */
|
|
|
|
static struct stm_tap_sysconf tap_sysconf = {
|
|
.tck = { SYS_CFG_BANK1, 3, 20, 20},
|
|
.tms = { SYS_CFG_BANK1, 3, 23, 23},
|
|
.tdi = { SYS_CFG_BANK1, 3, 22, 22},
|
|
.tdo = { SYS_STA_BANK1, 4, 1, 1},
|
|
.tap_en = { SYS_CFG_BANK1, 3, 13, 13},
|
|
.trstn = { SYS_CFG_BANK1, 3, 21, 21},
|
|
};
|
|
|
|
|
|
static struct stm_plat_tap_data stx7108_tap_platform_data = {
|
|
.miphy_first = 0,
|
|
.miphy_count = 2,
|
|
.miphy_modes = stx7108_miphy_modes,
|
|
.tap_sysconf = &tap_sysconf,
|
|
};
|
|
|
|
static struct platform_device stx7108_tap_device = {
|
|
.name = "stm-miphy-tap",
|
|
.id = 0,
|
|
.num_resources = 0,
|
|
.dev = {
|
|
.platform_data = &stx7108_tap_platform_data,
|
|
}
|
|
};
|
|
|
|
static int __init stx7108_configure_miphy_uport(void)
|
|
{
|
|
struct sysconf_field *sc_miphy1_ref_clk,
|
|
*sc_sata1_hc_reset, *sc_sata_pcie_sel,
|
|
*sc_sata1_hc_srst;
|
|
|
|
sc_pcie_mp_select = sysconf_claim(SYS_CFG_BANK4, 70,
|
|
0, 0, "pcie-mp");
|
|
BUG_ON(!sc_pcie_mp_select);
|
|
|
|
/* SATA0_SOFT_RST_N_SATA: sata0_soft_rst_n_sata. */
|
|
/* Useless documentation R us */
|
|
sc_sata1_hc_srst = sysconf_claim(SYS_CFG_BANK4, 45, 4, 4, "MiPHY");
|
|
BUG_ON(!sc_sata1_hc_srst);
|
|
|
|
/* SELECT_SATA: select_sata. */
|
|
sc_sata_pcie_sel = sysconf_claim(SYS_CFG_BANK4, 68, 1, 1, "MiPHY");
|
|
BUG_ON(!sc_sata_pcie_sel);
|
|
|
|
/* SATAPHY1_OSC_FORCE_EXT: SATAphy1_osc_force_ext. */
|
|
sc_miphy1_ref_clk = sysconf_claim(SYS_CFG_BANK4, 68, 2, 2, "MiPHY");
|
|
BUG_ON(!sc_miphy1_ref_clk);
|
|
|
|
/* RESETGEN_CONF0_1: Active low Software Reset for peripherals <31:0>.
|
|
* NOTE documenation appears to be wrong!
|
|
* RST_PER_N_30: SATA_2XHOST */
|
|
sc_sata1_hc_reset = sysconf_claim(SYS_CFG_BANK0,
|
|
BANK0_REG(12), 30, 30, "SATA");
|
|
BUG_ON(!sc_sata1_hc_reset);
|
|
|
|
/* Deassert Soft Reset to SATA0 */
|
|
sysconf_write(sc_sata1_hc_srst, 1);
|
|
|
|
/* If the 100MHz xtal for PCIe is present, then the microport interface
|
|
* will already have a clock, so there is no need to flip to the 30MHz
|
|
* clock here. If it isn't then we have to switch miphy lane 1 to use
|
|
* the 30MHz clock, as otherwise we will not be able to talk to lane 0
|
|
* since the uport interface itself is clocked from lane1
|
|
*/
|
|
if (stx7108_miphy_modes[1] != PCIE_MODE) {
|
|
/* Put MiPHY1 in reset - rst_per_n[32] */
|
|
sysconf_write(sc_miphy_reset[1], 0);
|
|
/* Put SATA1 HC in reset - rst_per_n[30] */
|
|
sysconf_write(sc_sata1_hc_reset, 0);
|
|
/* Now switch to Phy interface to SATA HC not PCIe HC */
|
|
sysconf_write(sc_sata_pcie_sel, 1);
|
|
/* Select the Uport to use MiPHY1 */
|
|
stx7108_pcie_mp_select(1);
|
|
/* Take SATA1 HC out of reset - rst_per_n[30] */
|
|
sysconf_write(sc_sata1_hc_reset, 1);
|
|
/* MiPHY1 needs to be using the MiPHY0 reference clock */
|
|
sysconf_write(sc_miphy1_ref_clk, 1);
|
|
/* Take MiPHY1 out of reset - rst_per_n[32] */
|
|
sysconf_write(sc_miphy_reset[1], 1);
|
|
}
|
|
|
|
stx7108_using_uport = 1;
|
|
|
|
return platform_device_register(&stx7108_pcie_mp_device);
|
|
}
|
|
|
|
static int __init stx7108_configure_miphy_tap(void)
|
|
{
|
|
return platform_device_register(&stx7108_tap_device);
|
|
}
|
|
|
|
void __init stx7108_configure_miphy(struct stx7108_miphy_config *config)
|
|
{
|
|
int err = 0;
|
|
|
|
memcpy(stx7108_miphy_modes, config->modes, sizeof(stx7108_miphy_modes));
|
|
|
|
/* RESETGEN_CONF0_1: Active low Software Reset for peripherals <31:0>.
|
|
* NOTE documenation appears to be wrong!
|
|
* RST_PER_N_31: SATA PHI 0 */
|
|
sc_miphy_reset[0] = sysconf_claim(SYS_CFG_BANK0,
|
|
BANK0_REG(12), 31, 31, "SATA");
|
|
BUG_ON(!sc_miphy_reset[0]);
|
|
|
|
/* RESETGEN_CONF0_2: Active low Software Reset for peripherals <63:32>.
|
|
* NOTE documenation appears to be wrong!
|
|
* RST_PER_N_32: SATA PHI 1 */
|
|
sc_miphy_reset[1] = sysconf_claim(SYS_CFG_BANK0,
|
|
BANK0_REG(13), 0, 0, "SATA");
|
|
BUG_ON(!sc_miphy_reset[1]);
|
|
|
|
if (cpu_data->cut_major >= 2 && !config->force_jtag)
|
|
err = stx7108_configure_miphy_uport();
|
|
else
|
|
err = stx7108_configure_miphy_tap();
|
|
}
|
|
|
|
|
|
|
|
/* SATA resources --------------------------------------------------------- */
|
|
|
|
static struct sysconf_field *sc_sata_hc_pwr[MAX_PORTS];
|
|
|
|
static void stx7108_restart_sata(int port)
|
|
{
|
|
/* This part of the code is executed for ESD recovery.
|
|
* However...
|
|
* It's Not supported on CUT1.0 As we have to reset both Lanes if there
|
|
* is a problem with single lane. As the MiPHY Code for JTAG_IF is
|
|
* not independent of lanes which will potentially results in a
|
|
* recursive resets among lane-0 and lane-1. This behaviour might
|
|
* make both disks unavailable.
|
|
*/
|
|
BUG_ON(cpu_data->cut_major < 2);
|
|
|
|
/* Reset the SATA Host and MiPHY */
|
|
sysconf_write(sc_sata_hc_pwr[port], 1);
|
|
sysconf_write(sc_miphy_reset[port], 0);
|
|
|
|
if (port == 1)
|
|
stx7108_pcie_mp_select(1);
|
|
|
|
msleep(1);
|
|
|
|
sysconf_write(sc_sata_hc_pwr[port], 0);
|
|
sysconf_write(sc_miphy_reset[port], 1);
|
|
}
|
|
|
|
static void stx7108_sata_power(struct stm_device_state *device_state,
|
|
int port, enum stm_device_power_state power)
|
|
{
|
|
int value = (power == stm_device_power_on) ? 0 : 1;
|
|
int i;
|
|
|
|
sysconf_write(sc_sata_hc_pwr[port], value);
|
|
|
|
for (i = 5; i; --i) {
|
|
if (stm_device_sysconf_read(device_state, "SATA_ACK")
|
|
== value)
|
|
break;
|
|
mdelay(10);
|
|
}
|
|
}
|
|
static void stx7108_sata0_power(struct stm_device_state *device_state,
|
|
enum stm_device_power_state power)
|
|
{
|
|
stx7108_sata_power(device_state, 0, power);
|
|
}
|
|
|
|
static void stx7108_sata1_power(struct stm_device_state *device_state,
|
|
enum stm_device_power_state power)
|
|
{
|
|
stx7108_sata_power(device_state, 1, power);
|
|
}
|
|
|
|
static struct platform_device stx7108_sata_devices[] = {
|
|
[0] = {
|
|
.name = "sata-stm",
|
|
.id = 0,
|
|
.dev.platform_data = &(struct stm_plat_sata_data) {
|
|
.phy_init = 0,
|
|
.pc_glue_logic_init = 0,
|
|
.only_32bit = 0,
|
|
.oob_wa = 1,
|
|
.port_num = 0,
|
|
.miphy_num = 0,
|
|
.device_config = &(struct stm_device_config){
|
|
.power = stx7108_sata0_power,
|
|
.sysconfs_num = 1,
|
|
.sysconfs = (struct stm_device_sysconf []) {
|
|
STM_DEVICE_SYS_STA_BANK(4, 2, 3, 3,
|
|
"SATA_ACK"),
|
|
},
|
|
},
|
|
},
|
|
.num_resources = 3,
|
|
.resource = (struct resource[]) {
|
|
STM_PLAT_RESOURCE_MEM(0xfe768000, 0x1000),
|
|
STM_PLAT_RESOURCE_IRQ_NAMED("hostc", ILC_IRQ(57), -1),
|
|
STM_PLAT_RESOURCE_IRQ_NAMED("dmac", ILC_IRQ(55), -1),
|
|
},
|
|
},
|
|
[1] = {
|
|
.name = "sata-stm",
|
|
.id = 1,
|
|
.dev.platform_data = &(struct stm_plat_sata_data) {
|
|
.phy_init = 0,
|
|
.pc_glue_logic_init = 0,
|
|
.only_32bit = 0,
|
|
.oob_wa = 1,
|
|
.port_num = 1,
|
|
.miphy_num = 1,
|
|
.device_config = &(struct stm_device_config){
|
|
.power = stx7108_sata1_power,
|
|
.sysconfs_num = 1,
|
|
.sysconfs = (struct stm_device_sysconf []) {
|
|
STM_DEVICE_SYS_STA_BANK(4, 2, 4, 4,
|
|
"SATA_ACK"),
|
|
},
|
|
},
|
|
},
|
|
.num_resources = 3,
|
|
.resource = (struct resource[]) {
|
|
STM_PLAT_RESOURCE_MEM(0xfe769000, 0x1000),
|
|
STM_PLAT_RESOURCE_IRQ_NAMED("hostc", ILC_IRQ(58), -1),
|
|
STM_PLAT_RESOURCE_IRQ_NAMED("dmac", ILC_IRQ(56), -1),
|
|
},
|
|
}
|
|
};
|
|
|
|
void __init stx7108_configure_sata(int port, struct stx7108_sata_config *config)
|
|
{
|
|
struct stm_plat_sata_data *sata_data;
|
|
static int initialized[ARRAY_SIZE(stx7108_sata_devices)];
|
|
|
|
sata_data = stx7108_sata_devices[port].dev.platform_data;
|
|
|
|
BUG_ON(initialized[port]++);
|
|
|
|
sc_sata_hc_pwr[port] = sysconf_claim(SYS_CFG_BANK4, 46,
|
|
3+port, 3+port, "SATA");
|
|
if (!sc_sata_hc_pwr[port]) {
|
|
BUG();
|
|
return;
|
|
}
|
|
|
|
/* If we're using the uPort then we can reset the two lanes
|
|
* independently. */
|
|
if (stx7108_using_uport)
|
|
sata_data->host_restart = stx7108_restart_sata;
|
|
|
|
platform_device_register(&stx7108_sata_devices[port]);
|
|
}
|