| /* |
| * Copyright 2009-2011 Freescale Semiconductor, Inc. |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License as |
| * published by the Free Software Foundation; either version 2 of |
| * the License, or (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
| * MA 02111-1307 USA |
| */ |
| |
| #include <common.h> |
| #include <asm/types.h> |
| #include <asm/io.h> |
| #include <asm/fsl_enet.h> |
| #include <asm/fsl_dtsec.h> |
| #include <fsl_mdio.h> |
| #include <phy.h> |
| |
| #include "fm.h" |
| |
| #define RCTRL_INIT (RCTRL_GRS | RCTRL_UPROM) |
| #define TCTRL_INIT TCTRL_GTS |
| #define MACCFG1_INIT MACCFG1_SOFT_RST |
| |
| #define MACCFG2_INIT (MACCFG2_PRE_LEN(0x7) | MACCFG2_LEN_CHECK | \ |
| MACCFG2_PAD_CRC | MACCFG2_FULL_DUPLEX | \ |
| MACCFG2_IF_MODE_NIBBLE) |
| |
| /* MAXFRM - maximum frame length register */ |
| #define MAXFRM_MASK 0x00003fff |
| |
| static void dtsec_init_mac(struct fsl_enet_mac *mac) |
| { |
| struct dtsec *regs = mac->base; |
| |
| /* soft reset */ |
| out_be32(®s->maccfg1, MACCFG1_SOFT_RST); |
| udelay(1000); |
| |
| /* clear soft reset, Rx/Tx MAC disable */ |
| out_be32(®s->maccfg1, 0); |
| |
| /* graceful stop rx */ |
| out_be32(®s->rctrl, RCTRL_INIT); |
| udelay(1000); |
| |
| /* graceful stop tx */ |
| out_be32(®s->tctrl, TCTRL_INIT); |
| udelay(1000); |
| |
| /* disable all interrupts */ |
| out_be32(®s->imask, IMASK_MASK_ALL); |
| |
| /* clear all events */ |
| out_be32(®s->ievent, IEVENT_CLEAR_ALL); |
| |
| /* set the max Rx length */ |
| out_be32(®s->maxfrm, mac->max_rx_len & MAXFRM_MASK); |
| |
| /* set the ecntrl to reset value */ |
| out_be32(®s->ecntrl, ECNTRL_DEFAULT); |
| |
| /* |
| * Rx length check, no strip CRC for Rx, pad and append CRC for Tx, |
| * full duplex |
| */ |
| out_be32(®s->maccfg2, MACCFG2_INIT); |
| } |
| |
| static void dtsec_enable_mac(struct fsl_enet_mac *mac) |
| { |
| struct dtsec *regs = mac->base; |
| |
| /* enable Rx/Tx MAC */ |
| setbits_be32(®s->maccfg1, MACCFG1_RXTX_EN); |
| |
| /* clear the graceful Rx stop */ |
| clrbits_be32(®s->rctrl, RCTRL_GRS); |
| |
| /* clear the graceful Tx stop */ |
| clrbits_be32(®s->tctrl, TCTRL_GTS); |
| } |
| |
| static void dtsec_disable_mac(struct fsl_enet_mac *mac) |
| { |
| struct dtsec *regs = mac->base; |
| |
| /* graceful Rx stop */ |
| setbits_be32(®s->rctrl, RCTRL_GRS); |
| |
| /* graceful Tx stop */ |
| setbits_be32(®s->tctrl, TCTRL_GTS); |
| |
| /* disable Rx/Tx MAC */ |
| clrbits_be32(®s->maccfg1, MACCFG1_RXTX_EN); |
| } |
| |
| static void dtsec_set_mac_addr(struct fsl_enet_mac *mac, u8 *mac_addr) |
| { |
| struct dtsec *regs = mac->base; |
| u32 mac_addr1, mac_addr2; |
| |
| /* |
| * if a station address of 0x12345678ABCD, perform a write to |
| * MACSTNADDR1 of 0xCDAB7856, MACSTNADDR2 of 0x34120000 |
| */ |
| mac_addr1 = (mac_addr[5] << 24) | (mac_addr[4] << 16) | \ |
| (mac_addr[3] << 8) | (mac_addr[2]); |
| out_be32(®s->macstnaddr1, mac_addr1); |
| |
| mac_addr2 = ((mac_addr[1] << 24) | (mac_addr[0] << 16)) & 0xffff0000; |
| out_be32(®s->macstnaddr2, mac_addr2); |
| } |
| |
| static void dtsec_set_interface_mode(struct fsl_enet_mac *mac, |
| phy_interface_t type, int speed) |
| { |
| struct dtsec *regs = mac->base; |
| u32 ecntrl, maccfg2; |
| |
| /* clear all bits relative with interface mode */ |
| ecntrl = in_be32(®s->ecntrl); |
| ecntrl &= ~(ECNTRL_TBIM | ECNTRL_GMIIM | ECNTRL_RPM | |
| ECNTRL_R100M | ECNTRL_SGMIIM); |
| |
| maccfg2 = in_be32(®s->maccfg2); |
| maccfg2 &= ~MACCFG2_IF_MODE_MASK; |
| |
| if (speed == SPEED_1000) |
| maccfg2 |= MACCFG2_IF_MODE_BYTE; |
| else |
| maccfg2 |= MACCFG2_IF_MODE_NIBBLE; |
| |
| /* set interface mode */ |
| switch (type) { |
| case PHY_INTERFACE_MODE_GMII: |
| ecntrl |= ECNTRL_GMIIM; |
| break; |
| case PHY_INTERFACE_MODE_RGMII: |
| ecntrl |= (ECNTRL_GMIIM | ECNTRL_RPM); |
| if (speed == SPEED_100) |
| ecntrl |= ECNTRL_R100M; |
| break; |
| case PHY_INTERFACE_MODE_RMII: |
| if (speed == SPEED_100) |
| ecntrl |= ECNTRL_R100M; |
| break; |
| case PHY_INTERFACE_MODE_SGMII: |
| ecntrl |= (ECNTRL_SGMIIM | ECNTRL_TBIM); |
| if (speed == SPEED_100) |
| ecntrl |= ECNTRL_R100M; |
| break; |
| default: |
| break; |
| } |
| |
| out_be32(®s->ecntrl, ecntrl); |
| out_be32(®s->maccfg2, maccfg2); |
| } |
| |
| void init_dtsec(struct fsl_enet_mac *mac, void *base, |
| void *phyregs, int max_rx_len) |
| { |
| mac->base = base; |
| mac->phyregs = NULL; |
| mac->max_rx_len = max_rx_len; |
| mac->init_mac = dtsec_init_mac; |
| mac->enable_mac = dtsec_enable_mac; |
| mac->disable_mac = dtsec_disable_mac; |
| mac->set_mac_addr = dtsec_set_mac_addr; |
| mac->set_if_mode = dtsec_set_interface_mode; |
| } |