int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con) { int dpmemsz, memsz; u8 *dp_mem; unsigned long dp_offset; u8 *mem_addr; dma_addr_t dma_addr = 0; pr_debug("CPM uart[%d]:allocbuf\n", pinfo->port.line); dpmemsz = sizeof(cbd_t) * (pinfo->rx_nrfifos + pinfo->tx_nrfifos); dp_offset = cpm_dpalloc(dpmemsz, 8); if (IS_ERR_VALUE(dp_offset)) { printk(KERN_ERR "cpm_uart_cpm1.c: could not allocate buffer descriptors\n"); return -ENOMEM; } dp_mem = cpm_dpram_addr(dp_offset); memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) + L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize); if (is_con) { mem_addr = (u8 *) cpm_dpram_addr(cpm_dpalloc(memsz, 8)); dma_addr = (u32)cpm_dpram_phys(mem_addr); } else mem_addr = dma_alloc_coherent(pinfo->port.dev, memsz, &dma_addr, GFP_KERNEL); if (mem_addr == NULL) { cpm_dpfree(dp_offset); printk(KERN_ERR "cpm_uart_cpm1.c: could not allocate coherent memory\n"); return -ENOMEM; } pinfo->dp_addr = dp_offset; pinfo->mem_addr = mem_addr; pinfo->dma_addr = dma_addr; pinfo->mem_size = memsz; pinfo->rx_buf = mem_addr; pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize); pinfo->rx_bd_base = (cbd_t __iomem __force *)dp_mem; pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos; return 0; }
/* * Allocate DP-Ram and memory buffers. We need to allocate a transmit and * receive buffer descriptors from dual port ram, and a character * buffer area from host mem. If we are allocating for the console we need * to do it from bootmem */ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con) { int dpmemsz, memsz; u8 *dp_mem; unsigned long dp_offset; u8 *mem_addr; dma_addr_t dma_addr = 0; pr_debug("CPM uart[%d]:allocbuf\n", pinfo->port.line); dpmemsz = sizeof(cbd_t) * (pinfo->rx_nrfifos + pinfo->tx_nrfifos); dp_offset = cpm_dpalloc(dpmemsz, 8); if (IS_ERR_VALUE(dp_offset)) { printk(KERN_ERR "cpm_uart_cpm1.c: could not allocate buffer descriptors\n"); return -ENOMEM; } dp_mem = cpm_dpram_addr(dp_offset); memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) + L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize); if (is_con) { /* was hostalloc but changed cause it blows away the */ /* large tlb mapping when pinning the kernel area */ mem_addr = (u8 *) cpm_dpram_addr(cpm_dpalloc(memsz, 8)); dma_addr = (u32)cpm_dpram_phys(mem_addr); } else mem_addr = dma_alloc_coherent(NULL, memsz, &dma_addr, GFP_KERNEL); if (mem_addr == NULL) { cpm_dpfree(dp_offset); printk(KERN_ERR "cpm_uart_cpm1.c: could not allocate coherent memory\n"); return -ENOMEM; } pinfo->dp_addr = dp_offset; pinfo->mem_addr = mem_addr; /* virtual address*/ pinfo->dma_addr = dma_addr; /* physical address*/ pinfo->mem_size = memsz; pinfo->rx_buf = mem_addr; pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize); pinfo->rx_bd_base = (volatile cbd_t *)dp_mem; pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos; return 0; }
void idma_pci9_init(void) { uint dpram_offset; volatile idma_t *pram; volatile im_idma_t *idma_reg; volatile cpm2_map_t *immap = cpm2_immr; /* allocate IDMA dpram */ dpram_offset = cpm_dpalloc(sizeof(idma_dpram_t), 64); idma_dpram = cpm_dpram_addr(dpram_offset); /* initialize the IDMA parameter RAM */ memset((void *)idma_dpram, 0, sizeof(idma_dpram_t)); pram = &idma_dpram->pram; pram->ibase = dpram_offset + IDMA_BD_OFFSET; pram->dpr_buf = dpram_offset + IDMA_XFER_BUF_OFFSET; pram->ss_max = 32; pram->dts = 32; /* initialize the IDMA_BASE pointer to the IDMA parameter RAM */ *((ushort *) &immap->im_dprambase[PROFF_IDMA]) = dpram_offset; /* initialize the IDMA registers */ idma_reg = (volatile im_idma_t *) &immap->im_sdma.sdma_idsr1; idma_reg[IDMA_CHAN].idmr = 0; /* mask all IDMA interrupts */ idma_reg[IDMA_CHAN].idsr = 0xff; /* clear all event flags */ printk("<4>Using IDMA%d for MPC8260 device erratum PCI 9 workaround\n", IDMA_CHAN + 1); return; }
/* * Allocate DP-Ram and memory buffers. We need to allocate a transmit and * receive buffer descriptors from dual port ram, and a character * buffer area from host mem. If we are allocating for the console we need * to do it from bootmem */ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con) { int dpmemsz, memsz; u8 *dp_mem; unsigned long dp_offset; u8 *mem_addr; dma_addr_t dma_addr = 0; pr_debug("CPM uart[%d]:allocbuf\n", pinfo->port.line); dpmemsz = sizeof(cbd_t) * (pinfo->rx_nrfifos + pinfo->tx_nrfifos); dp_offset = cpm_dpalloc(dpmemsz, 8); if (IS_ERR_VALUE(dp_offset)) { printk(KERN_ERR "cpm_uart_cpm.c: could not allocate buffer descriptors\n"); return -ENOMEM; } dp_mem = cpm_dpram_addr(dp_offset); memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) + L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize); if (is_con) { /* KGDB hits this before bootmem is setup */ if (init_bootmem_done) { mem_addr = alloc_bootmem(memsz); dma_addr = virt_to_bus(mem_addr); } else { dma_addr = (dma_addr_t)lmb_alloc(memsz, 8); mem_addr = __va(dma_addr); } } else mem_addr = dma_alloc_coherent(NULL, memsz, &dma_addr, GFP_KERNEL); if (mem_addr == NULL) { cpm_dpfree(dp_offset); printk(KERN_ERR "cpm_uart_cpm.c: could not allocate coherent memory\n"); return -ENOMEM; } pinfo->dp_addr = dp_offset; pinfo->mem_addr = mem_addr; pinfo->dma_addr = dma_addr; pinfo->mem_size = memsz; pinfo->rx_buf = mem_addr; pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize); pinfo->rx_bd_base = (volatile cbd_t *)dp_mem; pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos; return 0; }
static int allocate_bd(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); const struct fs_platform_info *fpi = fep->fpi; fep->ring_mem_addr = cpm_dpalloc((fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t), 8); if (IS_ERR_VALUE(fep->ring_mem_addr)) return -ENOMEM; fep->ring_base = (void __iomem __force*) cpm_dpram_addr(fep->ring_mem_addr); return 0; }
/* * Allocate DP-Ram and memory buffers. We need to allocate a transmit and * receive buffer descriptors from dual port ram, and a character * buffer area from host mem. If we are allocating for the console we need * to do it from bootmem */ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con) { int dpmemsz, memsz; u8 *dp_mem; uint dp_offset; u8 *mem_addr; dma_addr_t dma_addr = 0; pr_debug("CPM uart[%d]:allocbuf\n", pinfo->port.line); dpmemsz = sizeof(cbd_t) * (pinfo->rx_nrfifos + pinfo->tx_nrfifos); dp_offset = cpm_dpalloc(dpmemsz, 8); if (IS_DPERR(dp_offset)) { printk(KERN_ERR "cpm_uart_cpm.c: could not allocate buffer descriptors\n"); return -ENOMEM; } dp_mem = cpm_dpram_addr(dp_offset); memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) + L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize); if (is_con) mem_addr = alloc_bootmem(memsz); else mem_addr = dma_alloc_coherent(NULL, memsz, &dma_addr, GFP_KERNEL); if (mem_addr == NULL) { cpm_dpfree(dp_offset); printk(KERN_ERR "cpm_uart_cpm.c: could not allocate coherent memory\n"); return -ENOMEM; } pinfo->dp_addr = dp_offset; pinfo->mem_addr = mem_addr; pinfo->dma_addr = dma_addr; pinfo->rx_buf = mem_addr; pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize); pinfo->rx_bd_base = (volatile cbd_t *)dp_mem; pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos; return 0; }
/* Initialize the CPM Ethernet on SCC. If EPPC-Bug loaded us, or performed * some other network I/O, a whole bunch of this has already been set up. * It is no big deal if we do it again, we just have to disable the * transmit and receive to make sure we don't catch the CPM with some * inconsistent control information. */ static int __init scc_enet_init(void) { struct net_device *dev; struct scc_enet_private *cep; int i, j, k, err; uint dp_offset; unsigned char *eap, *ba; dma_addr_t mem_addr; bd_t *bd; volatile cbd_t *bdp; volatile cpm8xx_t *cp; volatile scc_t *sccp; volatile scc_enet_t *ep; volatile immap_t *immap; cp = cpmp; /* Get pointer to Communication Processor */ immap = (immap_t *)(mfspr(IMMR) & 0xFFFF0000); /* and to internal registers */ bd = (bd_t *)__res; dev = alloc_etherdev(sizeof(*cep)); if (!dev) return -ENOMEM; cep = dev->priv; spin_lock_init(&cep->lock); /* Get pointer to SCC area in parameter RAM. */ ep = (scc_enet_t *)(&cp->cp_dparam[PROFF_ENET]); /* And another to the SCC register area. */ sccp = (volatile scc_t *)(&cp->cp_scc[SCC_ENET]); cep->sccp = (scc_t *)sccp; /* Keep the pointer handy */ /* Disable receive and transmit in case EPPC-Bug started it. */ sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); /* Cookbook style from the MPC860 manual..... * Not all of this is necessary if EPPC-Bug has initialized * the network. * So far we are lucky, all board configurations use the same * pins, or at least the same I/O Port for these functions..... * It can't last though...... */ #if (defined(PA_ENET_RXD) && defined(PA_ENET_TXD)) /* Configure port A pins for Txd and Rxd. */ immap->im_ioport.iop_papar |= (PA_ENET_RXD | PA_ENET_TXD); immap->im_ioport.iop_padir &= ~(PA_ENET_RXD | PA_ENET_TXD); immap->im_ioport.iop_paodr &= ~PA_ENET_TXD; #elif (defined(PB_ENET_RXD) && defined(PB_ENET_TXD)) /* Configure port B pins for Txd and Rxd. */ immap->im_cpm.cp_pbpar |= (PB_ENET_RXD | PB_ENET_TXD); immap->im_cpm.cp_pbdir &= ~(PB_ENET_RXD | PB_ENET_TXD); immap->im_cpm.cp_pbodr &= ~PB_ENET_TXD; #else #error Exactly ONE pair of PA_ENET_[RT]XD, PB_ENET_[RT]XD must be defined #endif #if defined(PC_ENET_LBK) /* Configure port C pins to disable External Loopback */ immap->im_ioport.iop_pcpar &= ~PC_ENET_LBK; immap->im_ioport.iop_pcdir |= PC_ENET_LBK; immap->im_ioport.iop_pcso &= ~PC_ENET_LBK; immap->im_ioport.iop_pcdat &= ~PC_ENET_LBK; /* Disable Loopback */ #endif /* PC_ENET_LBK */ #ifdef PE_ENET_TCLK /* Configure port E for TCLK and RCLK. */ cp->cp_pepar |= (PE_ENET_TCLK | PE_ENET_RCLK); cp->cp_pedir &= ~(PE_ENET_TCLK | PE_ENET_RCLK); cp->cp_peso &= ~(PE_ENET_TCLK | PE_ENET_RCLK); #else /* Configure port A for TCLK and RCLK. */ immap->im_ioport.iop_papar |= (PA_ENET_TCLK | PA_ENET_RCLK); immap->im_ioport.iop_padir &= ~(PA_ENET_TCLK | PA_ENET_RCLK); #endif /* Configure port C pins to enable CLSN and RENA. */ immap->im_ioport.iop_pcpar &= ~(PC_ENET_CLSN | PC_ENET_RENA); immap->im_ioport.iop_pcdir &= ~(PC_ENET_CLSN | PC_ENET_RENA); immap->im_ioport.iop_pcso |= (PC_ENET_CLSN | PC_ENET_RENA); /* Configure Serial Interface clock routing. * First, clear all SCC bits to zero, then set the ones we want. */ cp->cp_sicr &= ~SICR_ENET_MASK; cp->cp_sicr |= SICR_ENET_CLKRT; /* Manual says set SDDR, but I can't find anything with that * name. I think it is a misprint, and should be SDCR. This * has already been set by the communication processor initialization. */ /* Allocate space for the buffer descriptors in the DP ram. * These are relative offsets in the DP ram address space. * Initialize base addresses for the buffer descriptors. */ dp_offset = cpm_dpalloc(sizeof(cbd_t) * RX_RING_SIZE, 8); ep->sen_genscc.scc_rbase = dp_offset; cep->rx_bd_base = cpm_dpram_addr(dp_offset); dp_offset = cpm_dpalloc(sizeof(cbd_t) * TX_RING_SIZE, 8); ep->sen_genscc.scc_tbase = dp_offset; cep->tx_bd_base = cpm_dpram_addr(dp_offset); cep->dirty_tx = cep->cur_tx = cep->tx_bd_base; cep->cur_rx = cep->rx_bd_base; /* Issue init Rx BD command for SCC. * Manual says to perform an Init Rx parameters here. We have * to perform both Rx and Tx because the SCC may have been * already running. * In addition, we have to do it later because we don't yet have * all of the BD control/status set properly. cp->cp_cpcr = mk_cr_cmd(CPM_CR_ENET, CPM_CR_INIT_RX) | CPM_CR_FLG; while (cp->cp_cpcr & CPM_CR_FLG); */ /* Initialize function code registers for big-endian. */ ep->sen_genscc.scc_rfcr = SCC_EB; ep->sen_genscc.scc_tfcr = SCC_EB; /* Set maximum bytes per receive buffer. * This appears to be an Ethernet frame size, not the buffer * fragment size. It must be a multiple of four. */ ep->sen_genscc.scc_mrblr = PKT_MAXBLR_SIZE; /* Set CRC preset and mask. */ ep->sen_cpres = 0xffffffff; ep->sen_cmask = 0xdebb20e3; ep->sen_crcec = 0; /* CRC Error counter */ ep->sen_alec = 0; /* alignment error counter */ ep->sen_disfc = 0; /* discard frame counter */ ep->sen_pads = 0x8888; /* Tx short frame pad character */ ep->sen_retlim = 15; /* Retry limit threshold */ ep->sen_maxflr = PKT_MAXBUF_SIZE; /* maximum frame length register */ ep->sen_minflr = PKT_MINBUF_SIZE; /* minimum frame length register */ ep->sen_maxd1 = PKT_MAXBLR_SIZE; /* maximum DMA1 length */ ep->sen_maxd2 = PKT_MAXBLR_SIZE; /* maximum DMA2 length */ /* Clear hash tables. */ ep->sen_gaddr1 = 0; ep->sen_gaddr2 = 0; ep->sen_gaddr3 = 0; ep->sen_gaddr4 = 0; ep->sen_iaddr1 = 0; ep->sen_iaddr2 = 0; ep->sen_iaddr3 = 0; ep->sen_iaddr4 = 0; /* Set Ethernet station address. */ eap = (unsigned char *)&(ep->sen_paddrh); for (i=5; i>=0; i--) *eap++ = dev->dev_addr[i] = bd->bi_enetaddr[i]; ep->sen_pper = 0; /* 'cause the book says so */ ep->sen_taddrl = 0; /* temp address (LSB) */ ep->sen_taddrm = 0; ep->sen_taddrh = 0; /* temp address (MSB) */ /* Now allocate the host memory pages and initialize the * buffer descriptors. */ bdp = cep->tx_bd_base; for (i=0; i<TX_RING_SIZE; i++) { /* Initialize the BD for every fragment in the page. */ bdp->cbd_sc = 0; bdp->cbd_bufaddr = 0; bdp++; } /* Set the last buffer to wrap. */ bdp--; bdp->cbd_sc |= BD_SC_WRAP; bdp = cep->rx_bd_base; k = 0; for (i=0; i<CPM_ENET_RX_PAGES; i++) { /* Allocate a page. */ ba = (unsigned char *)dma_alloc_coherent(NULL, PAGE_SIZE, &mem_addr, GFP_KERNEL); /* BUG: no check for failure */ /* Initialize the BD for every fragment in the page. */ for (j=0; j<CPM_ENET_RX_FRPPG; j++) { bdp->cbd_sc = BD_ENET_RX_EMPTY | BD_ENET_RX_INTR; bdp->cbd_bufaddr = mem_addr; cep->rx_vaddr[k++] = ba; mem_addr += CPM_ENET_RX_FRSIZE; ba += CPM_ENET_RX_FRSIZE; bdp++; } } /* Set the last buffer to wrap. */ bdp--; bdp->cbd_sc |= BD_SC_WRAP; /* Let's re-initialize the channel now. We have to do it later * than the manual describes because we have just now finished * the BD initialization. */ cp->cp_cpcr = mk_cr_cmd(CPM_CR_ENET, CPM_CR_INIT_TRX) | CPM_CR_FLG; while (cp->cp_cpcr & CPM_CR_FLG); cep->skb_cur = cep->skb_dirty = 0; sccp->scc_scce = 0xffff; /* Clear any pending events */ /* Enable interrupts for transmit error, complete frame * received, and any transmit buffer we have also set the * interrupt flag. */ sccp->scc_sccm = (SCCE_ENET_TXE | SCCE_ENET_RXF | SCCE_ENET_TXB); /* Install our interrupt handler. */ cpm_install_handler(CPMVEC_ENET, scc_enet_interrupt, dev); /* Set GSMR_H to enable all normal operating modes. * Set GSMR_L to enable Ethernet to MC68160. */ sccp->scc_gsmrh = 0; sccp->scc_gsmrl = (SCC_GSMRL_TCI | SCC_GSMRL_TPL_48 | SCC_GSMRL_TPP_10 | SCC_GSMRL_MODE_ENET); /* Set sync/delimiters. */ sccp->scc_dsr = 0xd555; /* Set processing mode. Use Ethernet CRC, catch broadcast, and * start frame search 22 bit times after RENA. */ sccp->scc_psmr = (SCC_PSMR_ENCRC | SCC_PSMR_NIB22); /* It is now OK to enable the Ethernet transmitter. * Unfortunately, there are board implementation differences here. */ #if (!defined (PB_ENET_TENA) && defined (PC_ENET_TENA) && !defined (PE_ENET_TENA)) immap->im_ioport.iop_pcpar |= PC_ENET_TENA; immap->im_ioport.iop_pcdir &= ~PC_ENET_TENA; #elif ( defined (PB_ENET_TENA) && !defined (PC_ENET_TENA) && !defined (PE_ENET_TENA)) cp->cp_pbpar |= PB_ENET_TENA; cp->cp_pbdir |= PB_ENET_TENA; #elif ( !defined (PB_ENET_TENA) && !defined (PC_ENET_TENA) && defined (PE_ENET_TENA)) cp->cp_pepar |= PE_ENET_TENA; cp->cp_pedir &= ~PE_ENET_TENA; cp->cp_peso |= PE_ENET_TENA; #else #error Configuration Error: define exactly ONE of PB_ENET_TENA, PC_ENET_TENA, PE_ENET_TENA #endif #if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC) /* And while we are here, set the configuration to enable ethernet. */ *((volatile uint *)RPX_CSR_ADDR) &= ~BCSR0_ETHLPBK; *((volatile uint *)RPX_CSR_ADDR) |= (BCSR0_ETHEN | BCSR0_COLTESTDIS | BCSR0_FULLDPLXDIS); #endif #ifdef CONFIG_BSEIP /* BSE uses port B and C for PHY control. */ cp->cp_pbpar &= ~(PB_BSE_POWERUP | PB_BSE_FDXDIS); cp->cp_pbdir |= (PB_BSE_POWERUP | PB_BSE_FDXDIS); cp->cp_pbdat |= (PB_BSE_POWERUP | PB_BSE_FDXDIS); immap->im_ioport.iop_pcpar &= ~PC_BSE_LOOPBACK; immap->im_ioport.iop_pcdir |= PC_BSE_LOOPBACK; immap->im_ioport.iop_pcso &= ~PC_BSE_LOOPBACK; immap->im_ioport.iop_pcdat &= ~PC_BSE_LOOPBACK; #endif #ifdef CONFIG_FADS cp->cp_pbpar |= PB_ENET_TENA; cp->cp_pbdir |= PB_ENET_TENA; /* Enable the EEST PHY. */ *((volatile uint *)BCSR1) &= ~BCSR1_ETHEN; #endif #ifdef CONFIG_MPC885ADS /* Deassert PHY reset and enable the PHY. */ { volatile uint __iomem *bcsr = ioremap(BCSR_ADDR, BCSR_SIZE); uint tmp; tmp = in_be32(bcsr + 1 /* BCSR1 */); tmp |= BCSR1_ETHEN; out_be32(bcsr + 1, tmp); tmp = in_be32(bcsr + 4 /* BCSR4 */); tmp |= BCSR4_ETH10_RST; out_be32(bcsr + 4, tmp); iounmap(bcsr); } /* On MPC885ADS SCC ethernet PHY defaults to the full duplex mode * upon reset. SCC is set to half duplex by default. So this * inconsistency should be better fixed by the software. */ #endif dev->base_addr = (unsigned long)ep; #if 0 dev->name = "CPM_ENET"; #endif /* The CPM Ethernet specific entries in the device structure. */ dev->open = scc_enet_open; dev->hard_start_xmit = scc_enet_start_xmit; dev->tx_timeout = scc_enet_timeout; dev->watchdog_timeo = TX_TIMEOUT; dev->stop = scc_enet_close; dev->get_stats = scc_enet_get_stats; dev->set_multicast_list = set_multicast_list; err = register_netdev(dev); if (err) { free_netdev(dev); return err; } /* And last, enable the transmit and receive processing. */ sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); printk("%s: CPM ENET Version 0.2 on SCC%d, ", dev->name, SCC_ENET+1); for (i=0; i<5; i++) printk("%02x:", dev->dev_addr[i]); printk("%02x\n", dev->dev_addr[5]); return 0; }
/* Initialize the CPM Ethernet on SCC. */ static int __init scc_enet_init(void) { struct net_device *dev; struct scc_enet_private *cep; int i, j, err; uint dp_offset; unsigned char *eap; unsigned long mem_addr; bd_t *bd; volatile cbd_t *bdp; volatile cpm_cpm2_t *cp; volatile scc_t *sccp; volatile scc_enet_t *ep; volatile cpm2_map_t *immap; volatile iop_cpm2_t *io; cp = cpmp; /* Get pointer to Communication Processor */ immap = (cpm2_map_t *)CPM_MAP_ADDR; /* and to internal registers */ io = &immap->im_ioport; bd = (bd_t *)__res; /* Create an Ethernet device instance. */ dev = alloc_etherdev(sizeof(*cep)); if (!dev) return -ENOMEM; cep = dev->priv; spin_lock_init(&cep->lock); /* Get pointer to SCC area in parameter RAM. */ ep = (scc_enet_t *)(&immap->im_dprambase[PROFF_ENET]); /* And another to the SCC register area. */ sccp = (volatile scc_t *)(&immap->im_scc[SCC_ENET]); cep->sccp = (scc_t *)sccp; /* Keep the pointer handy */ /* Disable receive and transmit in case someone left it running. */ sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); /* Configure port C and D pins for SCC Ethernet. This * won't work for all SCC possibilities....it will be * board/port specific. */ io->iop_pparc |= (PC_ENET_RENA | PC_ENET_CLSN | PC_ENET_TXCLK | PC_ENET_RXCLK); io->iop_pdirc &= ~(PC_ENET_RENA | PC_ENET_CLSN | PC_ENET_TXCLK | PC_ENET_RXCLK); io->iop_psorc &= ~(PC_ENET_RENA | PC_ENET_TXCLK | PC_ENET_RXCLK); io->iop_psorc |= PC_ENET_CLSN; io->iop_ppard |= (PD_ENET_RXD | PD_ENET_TXD | PD_ENET_TENA); io->iop_pdird |= (PD_ENET_TXD | PD_ENET_TENA); io->iop_pdird &= ~PD_ENET_RXD; io->iop_psord |= PD_ENET_TXD; io->iop_psord &= ~(PD_ENET_RXD | PD_ENET_TENA); /* Configure Serial Interface clock routing. * First, clear all SCC bits to zero, then set the ones we want. */ immap->im_cpmux.cmx_scr &= ~CMX_CLK_MASK; immap->im_cpmux.cmx_scr |= CMX_CLK_ROUTE; /* Allocate space for the buffer descriptors in the DP ram. * These are relative offsets in the DP ram address space. * Initialize base addresses for the buffer descriptors. */ dp_offset = cpm_dpalloc(sizeof(cbd_t) * RX_RING_SIZE, 8); ep->sen_genscc.scc_rbase = dp_offset; cep->rx_bd_base = (cbd_t *)cpm_dpram_addr(dp_offset); dp_offset = cpm_dpalloc(sizeof(cbd_t) * TX_RING_SIZE, 8); ep->sen_genscc.scc_tbase = dp_offset; cep->tx_bd_base = (cbd_t *)cpm_dpram_addr(dp_offset); cep->dirty_tx = cep->cur_tx = cep->tx_bd_base; cep->cur_rx = cep->rx_bd_base; ep->sen_genscc.scc_rfcr = CPMFCR_GBL | CPMFCR_EB; ep->sen_genscc.scc_tfcr = CPMFCR_GBL | CPMFCR_EB; /* Set maximum bytes per receive buffer. * This appears to be an Ethernet frame size, not the buffer * fragment size. It must be a multiple of four. */ ep->sen_genscc.scc_mrblr = PKT_MAXBLR_SIZE; /* Set CRC preset and mask. */ ep->sen_cpres = 0xffffffff; ep->sen_cmask = 0xdebb20e3; ep->sen_crcec = 0; /* CRC Error counter */ ep->sen_alec = 0; /* alignment error counter */ ep->sen_disfc = 0; /* discard frame counter */ ep->sen_pads = 0x8888; /* Tx short frame pad character */ ep->sen_retlim = 15; /* Retry limit threshold */ ep->sen_maxflr = PKT_MAXBUF_SIZE; /* maximum frame length register */ ep->sen_minflr = PKT_MINBUF_SIZE; /* minimum frame length register */ ep->sen_maxd1 = PKT_MAXBLR_SIZE; /* maximum DMA1 length */ ep->sen_maxd2 = PKT_MAXBLR_SIZE; /* maximum DMA2 length */ /* Clear hash tables. */ ep->sen_gaddr1 = 0; ep->sen_gaddr2 = 0; ep->sen_gaddr3 = 0; ep->sen_gaddr4 = 0; ep->sen_iaddr1 = 0; ep->sen_iaddr2 = 0; ep->sen_iaddr3 = 0; ep->sen_iaddr4 = 0; /* Set Ethernet station address. * * This is supplied in the board information structure, so we * copy that into the controller. */ eap = (unsigned char *)&(ep->sen_paddrh); for (i=5; i>=0; i--) *eap++ = dev->dev_addr[i] = bd->bi_enetaddr[i]; ep->sen_pper = 0; /* 'cause the book says so */ ep->sen_taddrl = 0; /* temp address (LSB) */ ep->sen_taddrm = 0; ep->sen_taddrh = 0; /* temp address (MSB) */ /* Now allocate the host memory pages and initialize the * buffer descriptors. */ bdp = cep->tx_bd_base; for (i=0; i<TX_RING_SIZE; i++) { /* Initialize the BD for every fragment in the page. */ bdp->cbd_sc = 0; bdp->cbd_bufaddr = 0; bdp++; } /* Set the last buffer to wrap. */ bdp--; bdp->cbd_sc |= BD_SC_WRAP; bdp = cep->rx_bd_base; for (i=0; i<CPM_ENET_RX_PAGES; i++) { /* Allocate a page. */ mem_addr = __get_free_page(GFP_KERNEL); /* BUG: no check for failure */ /* Initialize the BD for every fragment in the page. */ for (j=0; j<CPM_ENET_RX_FRPPG; j++) { bdp->cbd_sc = BD_ENET_RX_EMPTY | BD_ENET_RX_INTR; bdp->cbd_bufaddr = __pa(mem_addr); mem_addr += CPM_ENET_RX_FRSIZE; bdp++; } } /* Set the last buffer to wrap. */ bdp--; bdp->cbd_sc |= BD_SC_WRAP; /* Let's re-initialize the channel now. We have to do it later * than the manual describes because we have just now finished * the BD initialization. */ cpmp->cp_cpcr = mk_cr_cmd(CPM_ENET_PAGE, CPM_ENET_BLOCK, 0, CPM_CR_INIT_TRX) | CPM_CR_FLG; while (cp->cp_cpcr & CPM_CR_FLG); cep->skb_cur = cep->skb_dirty = 0; sccp->scc_scce = 0xffff; /* Clear any pending events */ /* Enable interrupts for transmit error, complete frame * received, and any transmit buffer we have also set the * interrupt flag. */ sccp->scc_sccm = (SCCE_ENET_TXE | SCCE_ENET_RXF | SCCE_ENET_TXB); /* Install our interrupt handler. */ request_irq(SIU_INT_ENET, scc_enet_interrupt, 0, "enet", dev); /* BUG: no check for failure */ /* Set GSMR_H to enable all normal operating modes. * Set GSMR_L to enable Ethernet to MC68160. */ sccp->scc_gsmrh = 0; sccp->scc_gsmrl = (SCC_GSMRL_TCI | SCC_GSMRL_TPL_48 | SCC_GSMRL_TPP_10 | SCC_GSMRL_MODE_ENET); /* Set sync/delimiters. */ sccp->scc_dsr = 0xd555; /* Set processing mode. Use Ethernet CRC, catch broadcast, and * start frame search 22 bit times after RENA. */ sccp->scc_psmr = (SCC_PSMR_ENCRC | SCC_PSMR_NIB22); /* It is now OK to enable the Ethernet transmitter. * Unfortunately, there are board implementation differences here. */ io->iop_pparc &= ~(PC_EST8260_ENET_LOOPBACK | PC_EST8260_ENET_SQE | PC_EST8260_ENET_NOTFD); io->iop_psorc &= ~(PC_EST8260_ENET_LOOPBACK | PC_EST8260_ENET_SQE | PC_EST8260_ENET_NOTFD); io->iop_pdirc |= (PC_EST8260_ENET_LOOPBACK | PC_EST8260_ENET_SQE | PC_EST8260_ENET_NOTFD); io->iop_pdatc &= ~(PC_EST8260_ENET_LOOPBACK | PC_EST8260_ENET_SQE); io->iop_pdatc |= PC_EST8260_ENET_NOTFD; dev->base_addr = (unsigned long)ep; /* The CPM Ethernet specific entries in the device structure. */ dev->open = scc_enet_open; dev->hard_start_xmit = scc_enet_start_xmit; dev->tx_timeout = scc_enet_timeout; dev->watchdog_timeo = TX_TIMEOUT; dev->stop = scc_enet_close; dev->get_stats = scc_enet_get_stats; dev->set_multicast_list = set_multicast_list; /* And last, enable the transmit and receive processing. */ sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); err = register_netdev(dev); if (err) { free_netdev(dev); return err; } printk("%s: SCC ENET Version 0.1, ", dev->name); for (i=0; i<5; i++) printk("%02x:", dev->dev_addr[i]); printk("%02x\n", dev->dev_addr[5]); return 0; }
static int __init fs_enet_of_init(void) { struct device_node *np; unsigned int i; struct platform_device *fs_enet_dev; struct resource res; int ret; for (np = NULL, i = 0; (np = of_find_compatible_node(np, "network", "fs_enet")) != NULL; i++) { struct resource r[4]; struct device_node *phy, *mdio; struct fs_platform_info fs_enet_data; const unsigned int *id, *phy_addr, *phy_irq; const void *mac_addr; const phandle *ph; const char *model; memset(r, 0, sizeof(r)); memset(&fs_enet_data, 0, sizeof(fs_enet_data)); ret = of_address_to_resource(np, 0, &r[0]); if (ret) goto err; r[0].name = fcc_regs; ret = of_address_to_resource(np, 1, &r[1]); if (ret) goto err; r[1].name = fcc_pram; ret = of_address_to_resource(np, 2, &r[2]); if (ret) goto err; r[2].name = fcc_regs_c; fs_enet_data.fcc_regs_c = r[2].start; of_irq_to_resource(np, 0, &r[3]); fs_enet_dev = platform_device_register_simple("fsl-cpm-fcc", i, &r[0], 4); if (IS_ERR(fs_enet_dev)) { ret = PTR_ERR(fs_enet_dev); goto err; } model = of_get_property(np, "model", NULL); if (model == NULL) { ret = -ENODEV; goto unreg; } mac_addr = of_get_mac_address(np); if (mac_addr) memcpy(fs_enet_data.macaddr, mac_addr, 6); ph = of_get_property(np, "phy-handle", NULL); phy = of_find_node_by_phandle(*ph); if (phy == NULL) { ret = -ENODEV; goto unreg; } phy_addr = of_get_property(phy, "reg", NULL); fs_enet_data.phy_addr = *phy_addr; phy_irq = of_get_property(phy, "interrupts", NULL); id = of_get_property(np, "device-id", NULL); fs_enet_data.fs_no = *id; strcpy(fs_enet_data.fs_type, model); mdio = of_get_parent(phy); ret = of_address_to_resource(mdio, 0, &res); if (ret) { of_node_put(phy); of_node_put(mdio); goto unreg; } fs_enet_data.clk_rx = *((u32 *)of_get_property(np, "rx-clock", NULL)); fs_enet_data.clk_tx = *((u32 *)of_get_property(np, "tx-clock", NULL)); if (strstr(model, "FCC")) { int fcc_index = *id - 1; const unsigned char *mdio_bb_prop; fs_enet_data.dpram_offset = (u32)cpm_dpram_addr(0); fs_enet_data.rx_ring = 32; fs_enet_data.tx_ring = 32; fs_enet_data.rx_copybreak = 240; fs_enet_data.use_napi = 0; fs_enet_data.napi_weight = 17; fs_enet_data.mem_offset = FCC_MEM_OFFSET(fcc_index); fs_enet_data.cp_page = CPM_CR_FCC_PAGE(fcc_index); fs_enet_data.cp_block = CPM_CR_FCC_SBLOCK(fcc_index); snprintf((char*)&bus_id[(*id)], BUS_ID_SIZE, "%x:%02x", (u32)res.start, fs_enet_data.phy_addr); fs_enet_data.bus_id = (char*)&bus_id[(*id)]; fs_enet_data.init_ioports = init_fcc_ioports; mdio_bb_prop = of_get_property(phy, "bitbang", NULL); if (mdio_bb_prop) { struct platform_device *fs_enet_mdio_bb_dev; struct fs_mii_bb_platform_info fs_enet_mdio_bb_data; fs_enet_mdio_bb_dev = platform_device_register_simple("fsl-bb-mdio", i, NULL, 0); memset(&fs_enet_mdio_bb_data, 0, sizeof(struct fs_mii_bb_platform_info)); fs_enet_mdio_bb_data.mdio_dat.bit = mdio_bb_prop[0]; fs_enet_mdio_bb_data.mdio_dir.bit = mdio_bb_prop[1]; fs_enet_mdio_bb_data.mdc_dat.bit = mdio_bb_prop[2]; fs_enet_mdio_bb_data.mdio_port = mdio_bb_prop[3]; fs_enet_mdio_bb_data.mdc_port = mdio_bb_prop[4]; fs_enet_mdio_bb_data.delay = mdio_bb_prop[5]; fs_enet_mdio_bb_data.irq[0] = phy_irq[0]; fs_enet_mdio_bb_data.irq[1] = -1; fs_enet_mdio_bb_data.irq[2] = -1; fs_enet_mdio_bb_data.irq[3] = phy_irq[0]; fs_enet_mdio_bb_data.irq[31] = -1; fs_enet_mdio_bb_data.mdio_dat.offset = (u32)&cpm2_immr->im_ioport.iop_pdatc; fs_enet_mdio_bb_data.mdio_dir.offset = (u32)&cpm2_immr->im_ioport.iop_pdirc; fs_enet_mdio_bb_data.mdc_dat.offset = (u32)&cpm2_immr->im_ioport.iop_pdatc; ret = platform_device_add_data( fs_enet_mdio_bb_dev, &fs_enet_mdio_bb_data, sizeof(struct fs_mii_bb_platform_info)); if (ret) goto unreg; } of_node_put(phy); of_node_put(mdio); ret = platform_device_add_data(fs_enet_dev, &fs_enet_data, sizeof(struct fs_platform_info)); if (ret) goto unreg; } } return 0; unreg: platform_device_unregister(fs_enet_dev); err: return ret; }