@@ -76,9 +76,9 @@ enum power_event {
#define LPI_CTRL_STATUS_TLPIEN 0x00000001 /* Transmit LPI Entry */
/* GMAC HW ADDR regs */
-#define GMAC_ADDR_HIGH(reg) ((reg > 15) ? 0x00000800 + (reg - 16) * 8 : \
+#define GMAC_ADDR_HIGH(reg, x) ((reg > 15) ? 0x00000800 + (reg - 16) * 8 * (x) : \
0x00000040 + (reg * 8))
-#define GMAC_ADDR_LOW(reg) ((reg > 15) ? 0x00000804 + (reg - 16) * 8 : \
+#define GMAC_ADDR_LOW(reg, x) ((reg > 15) ? 0x00000804 + (reg - 16) * 8 * (x) : \
0x00000044 + (reg * 8))
#define GMAC_MAX_PERFECT_ADDRESSES 1
@@ -24,6 +24,7 @@
static void dwmac1000_core_init(struct mac_device_info *hw,
struct net_device *dev)
{
+ struct stmmac_priv *priv = netdev_priv(dev);
void __iomem *ioaddr = hw->pcsr;
u32 value = readl(ioaddr + GMAC_CONTROL);
int mtu = dev->mtu;
@@ -31,6 +32,9 @@ static void dwmac1000_core_init(struct mac_device_info *hw,
/* Configure GMAC core */
value |= GMAC_CORE_INIT;
+ if (priv->plat->dwmac_is_loongson)
+ value |= GMAC_CONTROL_ACS;
+
if (mtu > 1500)
value |= GMAC_CONTROL_2K;
if (mtu > 2000)
@@ -100,9 +104,10 @@ static void dwmac1000_set_umac_addr(struct stmmac_priv *priv,
const unsigned char *addr,
unsigned int reg_n)
{
+ bool is_loongson = priv->plat->dwmac_is_loongson;
void __iomem *ioaddr = hw->pcsr;
- stmmac_set_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),
- GMAC_ADDR_LOW(reg_n));
+ stmmac_set_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n, !is_loongson),
+ GMAC_ADDR_LOW(reg_n, !is_loongson));
}
static void dwmac1000_get_umac_addr(struct stmmac_priv *priv,
@@ -110,9 +115,10 @@ static void dwmac1000_get_umac_addr(struct stmmac_priv *priv,
unsigned char *addr,
unsigned int reg_n)
{
+ bool is_loongson = priv->plat->dwmac_is_loongson;
void __iomem *ioaddr = hw->pcsr;
- stmmac_get_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),
- GMAC_ADDR_LOW(reg_n));
+ stmmac_get_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n, !is_loongson),
+ GMAC_ADDR_LOW(reg_n, !is_loongson));
}
static void dwmac1000_set_mchash(void __iomem *ioaddr, u32 *mcfilterbits,
@@ -144,6 +150,7 @@ static void dwmac1000_set_filter(struct stmmac_priv *priv,
struct mac_device_info *hw,
struct net_device *dev)
{
+ bool is_loongson = priv->plat->dwmac_is_loongson;
void __iomem *ioaddr = (void __iomem *)dev->base_addr;
unsigned int value = 0;
unsigned int perfect_addr_number = hw->unicast_filter_entries;
@@ -156,7 +163,9 @@ static void dwmac1000_set_filter(struct stmmac_priv *priv,
memset(mc_filter, 0, sizeof(mc_filter));
if (dev->flags & IFF_PROMISC) {
- value = GMAC_FRAME_FILTER_PR | GMAC_FRAME_FILTER_PCF;
+ value = GMAC_FRAME_FILTER_PR;
+ if (!is_loongson)
+ value |= GMAC_FRAME_FILTER_PCF;
} else if (dev->flags & IFF_ALLMULTI) {
value = GMAC_FRAME_FILTER_PM; /* pass all multi */
} else if (!netdev_mc_empty(dev) && (mcbitslog2 == 0)) {
@@ -200,14 +209,14 @@ static void dwmac1000_set_filter(struct stmmac_priv *priv,
netdev_for_each_uc_addr(ha, dev) {
stmmac_set_mac_addr(ioaddr, ha->addr,
- GMAC_ADDR_HIGH(reg),
- GMAC_ADDR_LOW(reg));
+ GMAC_ADDR_HIGH(reg, !is_loongson),
+ GMAC_ADDR_LOW(reg, !is_loongson));
reg++;
}
while (reg < perfect_addr_number) {
- writel(0, ioaddr + GMAC_ADDR_HIGH(reg));
- writel(0, ioaddr + GMAC_ADDR_LOW(reg));
+ writel(0, ioaddr + GMAC_ADDR_HIGH(reg, !is_loongson));
+ writel(0, ioaddr + GMAC_ADDR_LOW(reg, !is_loongson));
reg++;
}
}
@@ -562,8 +571,20 @@ int dwmac1000_setup(struct stmmac_priv *priv)
{
dev_info(priv->device, "\tDWMAC1000\n");
- priv->plat->dwmac_is_loongson = false;
- priv->plat->dwmac_regs = &dwmac_default_dma_regs;
+ if (priv->plat->dma_cfg->dma64)
+ priv->plat->dwmac_regs = &dwmac_loongson64_dma_regs;
+ else
+ priv->plat->dwmac_regs = &dwmac_default_dma_regs;
+
+ return _dwmac1000_setup(priv);
+}
+
+int dwmac_loongson_setup(struct stmmac_priv *priv)
+{
+ dev_info(priv->device, "\tDWMAC1000(LOONGSON)\n");
+
+ priv->plat->dwmac_is_loongson = true;
+ priv->plat->dwmac_regs = &dwmac_loongson_dma_regs;
return _dwmac1000_setup(priv);
}
@@ -329,8 +329,14 @@ static int dwmac1000_get_hw_feature(struct stmmac_priv *priv,
dma_cap->rx_coe_type2 = (hw_cap & DMA_HW_FEAT_RXTYP2COE) >> 18;
dma_cap->rxfifo_over_2048 = (hw_cap & DMA_HW_FEAT_RXFIFOSIZE) >> 19;
/* TX and RX number of channels */
- dma_cap->number_rx_channel = (hw_cap & DMA_HW_FEAT_RXCHCNT) >> 20;
- dma_cap->number_tx_channel = (hw_cap & DMA_HW_FEAT_TXCHCNT) >> 22;
+ if (priv->plat->dwmac_is_loongson &&
+ ((hw_cap & (DMA_HW_FEAT_RXCHCNT | DMA_HW_FEAT_TXCHCNT)) >> 20) == 0) {
+ dma_cap->number_rx_channel = 8;
+ dma_cap->number_tx_channel = 8;
+ } else {
+ dma_cap->number_rx_channel = (hw_cap & DMA_HW_FEAT_RXCHCNT) >> 20;
+ dma_cap->number_tx_channel = (hw_cap & DMA_HW_FEAT_TXCHCNT) >> 22;
+ }
/* Alternate (enhanced) DESC mode */
dma_cap->enh_desc = (hw_cap & DMA_HW_FEAT_ENHDESSEL) >> 24;
@@ -160,6 +160,8 @@
#define NUM_DWMAC4_DMA_REGS 27
extern const struct dwmac_regs dwmac_default_dma_regs;
+extern const struct dwmac_regs dwmac_loongson_dma_regs;
+extern const struct dwmac_regs dwmac_loongson64_dma_regs;
void dwmac_enable_dma_transmission(struct stmmac_priv *priv,
void __iomem *ioaddr, u32 chan);
@@ -20,6 +20,21 @@ static const struct dwmac_dma_addrs default_dma_addrs = {
.cur_rx_buf_addr = 0x00001054
};
+static const struct dwmac_dma_addrs loongson_dma_addrs = {
+ .chan_offset = 0x100,
+ .rcv_base_addr = 0x0000100c,
+ .tx_base_addr = 0x00001010,
+ .cur_tx_buf_addr = 0x00001050,
+ .cur_rx_buf_addr = 0x00001054
+};
+
+static const struct dwmac_dma_addrs loongson64_dma_addrs = {
+ .rcv_base_addr = 0x00001090,
+ .tx_base_addr = 0x00001098,
+ .cur_tx_buf_addr = 0x000010b0,
+ .cur_rx_buf_addr = 0x000010b8
+};
+
static const struct dwmac_dma_axi default_dma_axi = {
.wr_osr_lmt = GENMASK(23, 20),
.wr_osr_lmt_shift = 20,
@@ -30,11 +45,26 @@ static const struct dwmac_dma_axi default_dma_axi = {
.osr_max = 0xf
};
+static const struct dwmac_dma_axi loongson_dma_axi = {
+ .wr_osr_lmt = BIT(20),
+ .wr_osr_lmt_shift = 20,
+ .wr_osr_lmt_mask = 0x1,
+ .rd_osr_lmt = BIT(16),
+ .rd_osr_lmt_shift = 16,
+ .rd_osr_lmt_mask = 0x1,
+ .osr_max = 0x1
+};
+
static const struct dwmac_dma_intr_ena default_dma_intr_ena = {
.nie = 0x00010000,
.aie = 0x00008000
};
+static const struct dwmac_dma_intr_ena loongson_dma_intr_ena = {
+ .nie = 0x00060000,
+ .aie = 0x00018000
+};
+
static const struct dwmac_dma_status default_dma_status = {
.glpii = 0x40000000,
.eb_mask = 0x00380000,
@@ -47,6 +77,18 @@ static const struct dwmac_dma_status default_dma_status = {
.fbi = 0x00002000
};
+static const struct dwmac_dma_status loongson_dma_status = {
+ .glpii = 0x10000000,
+ .eb_mask = 0x0e000000,
+ .ts_mask = 0x01c00000,
+ .ts_shift = 22,
+ .rs_mask = 0x00380000,
+ .rs_shift = 19,
+ .nis = 0x00040000 | 0x00020000,
+ .ais = 0x00010000 | 0x00008000,
+ .fbi = 0x00002000 | 0x00001000
+};
+
const struct dwmac_regs dwmac_default_dma_regs = {
.addrs = &default_dma_addrs,
.axi = &default_dma_axi,
@@ -54,17 +96,37 @@ const struct dwmac_regs dwmac_default_dma_regs = {
.status = &default_dma_status
};
+const struct dwmac_regs dwmac_loongson_dma_regs = {
+ .addrs = &loongson_dma_addrs,
+ .axi = &loongson_dma_axi,
+ .intr_ena = &loongson_dma_intr_ena,
+ .status = &loongson_dma_status
+};
+
+const struct dwmac_regs dwmac_loongson64_dma_regs = {
+ .addrs = &loongson64_dma_addrs,
+ .axi = &loongson_dma_axi,
+ .intr_ena = &default_dma_intr_ena,
+ .status = &default_dma_status
+};
+
int dwmac_dma_reset(void __iomem *ioaddr)
{
+ int err;
+ int cnt = 5;
u32 value = readl(ioaddr + DMA_BUS_MODE);
/* DMA SW reset */
- value |= DMA_BUS_MODE_SFT_RESET;
- writel(value, ioaddr + DMA_BUS_MODE);
+ do {
+ value |= DMA_BUS_MODE_SFT_RESET;
+ writel(value, ioaddr + DMA_BUS_MODE);
+
+ err = readl_poll_timeout(ioaddr + DMA_BUS_MODE, value,
+ !(value & DMA_BUS_MODE_SFT_RESET),
+ 10000, 200000);
+ } while (cnt-- && err);
- return readl_poll_timeout(ioaddr + DMA_BUS_MODE, value,
- !(value & DMA_BUS_MODE_SFT_RESET),
- 10000, 200000);
+ return err;
}
/* CSR1 enables the transmit DMA to check for new descriptor */
@@ -267,12 +329,16 @@ int dwmac_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
x->rx_early_irq++;
}
/* Optional hardware blocks, interrupts should be disabled */
- if (unlikely(intr_status &
- (DMA_STATUS_GPI | DMA_STATUS_GMI | DMA_STATUS_GLI)))
+ if (!priv->plat->dwmac_is_loongson &&
+ unlikely(intr_status & (DMA_STATUS_GPI | DMA_STATUS_GMI | DMA_STATUS_GLI)))
pr_warn("%s: unexpected status %08x\n", __func__, intr_status);
- /* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */
- writel((intr_status & 0x1ffff), ioaddr + DMA_STATUS);
+ if (priv->plat->dwmac_is_loongson)
+ writel((intr_status & 0x7ffff), ioaddr + DMA_STATUS);
+ else {
+ /* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */
+ writel((intr_status & 0x1ffff), ioaddr + DMA_STATUS);
+ }
return ret;
}
Add definitions for Loongson platform. Signed-off-by: Feiyang Chen <chenfeiyang@loongson.cn> --- .../net/ethernet/stmicro/stmmac/dwmac1000.h | 4 +- .../ethernet/stmicro/stmmac/dwmac1000_core.c | 43 +++++++--- .../ethernet/stmicro/stmmac/dwmac1000_dma.c | 10 ++- .../net/ethernet/stmicro/stmmac/dwmac_dma.h | 2 + .../net/ethernet/stmicro/stmmac/dwmac_lib.c | 84 +++++++++++++++++-- 5 files changed, 119 insertions(+), 24 deletions(-)