/* * (c) 2010 STMicroelectronics Limited * * Author: Pawel Moll * * 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 #include #include #include #include #include #include #include #include #include #include #include #include /* -------------------------------------------------------------------- * 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]); }