📄 dev_mpc860.c
字号:
/* Update an IDMA status register */static int mpc860_idma_update_idsr(struct mpc860_data *d,u_int id){ u_int cpm_int; switch(id) { case 0: cpm_int = MPC860_CIPR_IDMA1; break; case 1: cpm_int = MPC860_CIPR_IDMA2; break; default: return(-1); } if (d->idsr[id] & d->idmr[id]) d->cipr |= cpm_int; else d->cipr &= ~cpm_int; mpc860_update_cpm_int_status(d); return(0);}/* Process to an IDMA transfer for the specified buffer descriptor */static void mpc860_idma_transfer(struct mpc860_data *d, struct mpc860_idma_bd *bd){ physmem_dma_transfer(d->vm,bd->src_bp,bd->dst_bp,bd->buf_len);}/* Fetch an IDMA descriptor from Dual-Port RAM */static int mpc860_idma_fetch_bd(struct mpc860_data *d,m_uint16_t bd_addr, struct mpc860_idma_bd *bd){ if ((bd_addr < MPC860_DPRAM_OFFSET) || (bd_addr > MPC860_DPRAM_END)) return(-1); bd->offset = bd_addr - MPC860_DPRAM_OFFSET; /* Fetch control word */ bd->ctrl = dpram_r16(d,bd->offset+0x00); /* Fetch function code registers */ bd->dfcr = dpram_r8(d,bd->offset+0x02); bd->sfcr = dpram_r8(d,bd->offset+0x03); /* Fetch buffer length, source and destination addresses */ bd->buf_len = dpram_r32(d,bd->offset+0x04); bd->src_bp = dpram_r32(d,bd->offset+0x08); bd->dst_bp = dpram_r32(d,bd->offset+0x0c);#if DEBUG_IDMA MPC_LOG(d,"fetched IDMA BD at 0x%4.4x, src_bp=0x%8.8x, dst_bp=0x%8.8x " "len=%d\n",bd->offset,bd->src_bp,bd->dst_bp,bd->buf_len);#endif return(0);}/* Start an IDMA channel */static int mpc860_idma_start_channel(struct mpc860_data *d,u_int id){ struct mpc860_idma_bd bd; m_uint16_t dma_base,ibase,bd_offset; switch(id) { case 0: dma_base = MPC860_IDMA1_BASE; break; case 1: dma_base = MPC860_IDMA2_BASE; break; default: return(-1); } /* Get the IBASE register (offset 0) */ ibase = bd_offset = dpram_r16(d,dma_base+0x00); while(1) { /* Fetch a descriptor */ if (mpc860_idma_fetch_bd(d,bd_offset,&bd) == -1) return(-1); if (!(bd.ctrl & MPC860_IDMA_CTRL_V)) { d->idsr[id] |= MPC860_IDSR_OB; break; } /* Run the DMA transfer */ mpc860_idma_transfer(d,&bd); /* Clear the Valid bit */ bd.ctrl &= ~MPC860_IDMA_CTRL_V; dpram_w16(d,bd_offset-MPC860_DPRAM_OFFSET+0x00,bd.ctrl); /* Generate an interrupt for this buffer ? */ if (bd.ctrl & MPC860_IDMA_CTRL_I) d->idsr[id] |= MPC860_IDSR_AD; /* Stop if this is the last buffer of chain */ if (bd.ctrl & MPC860_IDMA_CTRL_L) { d->idsr[id] |= MPC860_IDSR_DONE; break; } bd_offset += sizeof(MPC860_IDMA_BD_SIZE); } mpc860_idma_update_idsr(d,id); return(0);}/* ======================================================================== *//* SPI (Serial Peripheral Interface) *//* ======================================================================== *//* Initialize SPI RX parameters */static void mpc860_spi_init_rx_params(struct mpc860_data *d){ m_uint16_t spi_base,rbase; spi_base = dpram_r16(d,MPC860_SPI_BASE_ADDR); /* Get the RBASE (offset 0) and store it in RBPTR */ rbase = dpram_r16(d,spi_base+0x00); dpram_w16(d,spi_base+0x10,rbase);}/* Initialize SPI TX parameters */static void mpc860_spi_init_tx_params(struct mpc860_data *d){ m_uint16_t spi_base,tbase; spi_base = dpram_r16(d,MPC860_SPI_BASE_ADDR); /* Get the TBASE (offset 2) and store it in TBPTR */ tbase = dpram_r16(d,spi_base+0x02); dpram_w16(d,spi_base+0x20,tbase);}/* Initialize SPI RX/TX parameters */static void mpc860_spi_init_rx_tx_params(struct mpc860_data *d){ mpc860_spi_init_rx_params(d); mpc860_spi_init_tx_params(d);}/* Fetch a SPI buffer descriptor */static int mpc860_spi_fetch_bd(struct mpc860_data *d,m_uint16_t bd_addr, struct mpc860_spi_bd *bd){ void *ptr; if ((bd_addr < MPC860_DPRAM_OFFSET) || (bd_addr > MPC860_DPRAM_END)) return(-1); bd->offset = bd_addr - MPC860_DPRAM_OFFSET; ptr = &d->dpram[bd->offset]; /* Fetch control word */ bd->ctrl = dpram_r16(d,bd->offset+0x00); /* Fetch buffer length and buffer pointer */ bd->buf_len = dpram_r16(d,bd->offset+0x02); bd->bp = dpram_r32(d,bd->offset+0x04);#if DEBUG_SPI MPC_LOG(d,"fetched SPI BD at 0x%4.4x, bp=0x%8.8x, len=%d\n", bd->offset,bd->bp,bd->buf_len);#endif return(0);}/* Start SPI transmit */static int mpc860_spi_start_tx(struct mpc860_data *d){ struct mpc860_spi_bd bd; m_uint16_t bd_offset; m_uint16_t spi_base; u_char buffer[512]; u_int buf_len; spi_base = dpram_r16(d,MPC860_SPI_BASE_ADDR); /* Get the TBPTR (offset 0x20) register */ bd_offset = dpram_r16(d,spi_base+0x20); while(1) { /* Fetch a TX descriptor */ if (mpc860_spi_fetch_bd(d,bd_offset,&bd) == -1) return(FALSE); /* If the descriptor is not ready, stop now */ if (!(bd.ctrl & MPC860_SPI_TXBD_CTRL_R)) return(FALSE); /* Extract the data */ buf_len = bd.buf_len; if (bd.buf_len > sizeof(buffer)) { MPC_LOG(d,"SPI: buffer too small for transmit.\n"); buf_len = sizeof(buffer); } physmem_copy_from_vm(d->vm,buffer,bd.bp,buf_len); /* Send the data to the user callback (if specified) */ if (d->spi_tx_callback != NULL) d->spi_tx_callback(d,buffer,buf_len,d->spi_user_arg); /* Clear the Ready bit of the TX descriptor */ bd.ctrl &= ~MPC860_SPI_TXBD_CTRL_R; dpram_w16(d,bd.offset+0x00,bd.ctrl); /* Set pointer on next TX descriptor (wrap ring if necessary) */ if (bd.ctrl & MPC860_SPI_TXBD_CTRL_W) { bd_offset = dpram_r16(d,spi_base+0x02); } else { bd_offset += MPC860_SPI_BD_SIZE; } dpram_w16(d,spi_base+0x20,bd_offset); /* Stop if this is the last buffer in chain */ if (bd.ctrl & MPC860_SPI_TXBD_CTRL_L) break; } return(TRUE);}/* Put a buffer into SPI receive buffers */int mpc860_spi_receive(struct mpc860_data *d,u_char *buffer,u_int len){ struct mpc860_spi_bd bd; m_uint16_t bd_offset; m_uint16_t spi_base; u_int clen,mrblr; spi_base = dpram_r16(d,MPC860_SPI_BASE_ADDR); /* Get the RBPTR (offset 0x10) */ bd_offset = dpram_r16(d,spi_base+0x10); /* Get the maximum buffer size */ mrblr = dpram_r16(d,spi_base+0x06); while(len > 0) { /* Fetch a RX descriptor */ if (mpc860_spi_fetch_bd(d,bd_offset,&bd) == -1) return(FALSE); /* If the buffer is not empty, do not use it */ if (!(bd.ctrl & MPC860_SPI_RXBD_CTRL_E)) return(FALSE); /* Write data into the RX buffer */ clen = m_min(mrblr,len); physmem_copy_to_vm(d->vm,buffer,bd.bp,clen); buffer += clen; len -= clen; /* Update the length field */ dpram_w16(d,bd.offset+0x02,clen); /* If no more data, set the "Last" bit */ if (!len) bd.ctrl |= MPC860_SPI_RXBD_CTRL_L; /* Clear the Empty bit of the RX descriptor */ bd.ctrl &= ~MPC860_SPI_RXBD_CTRL_E; dpram_w16(d,bd.offset+0x00,bd.ctrl); /* Set pointer on next RX descriptor */ if (bd.ctrl & MPC860_SPI_RXBD_CTRL_W) { bd_offset = dpram_r16(d,spi_base+0x00); } else { bd_offset += MPC860_SPI_BD_SIZE; } dpram_w16(d,spi_base+0x10,bd_offset); } if (len > 0) MPC_LOG(d,"SPI: no buffers available for receive.\n"); return(0);}/* Set SPI TX callback */void mpc860_spi_set_tx_callback(struct mpc860_data *d, mpc860_spi_tx_callback_t cbk, void *user_arg){ d->spi_tx_callback = cbk; d->spi_user_arg = user_arg;}/* ======================================================================== *//* SCC (Serial Communication Controller) *//* ======================================================================== */typedef struct { u_int cipr_irq; m_uint32_t dpram_base;}scc_chan_info_t;static scc_chan_info_t scc_chan_info[MPC860_SCC_NR_CHAN] = { { MPC860_CIPR_SCC1, MPC860_SCC1_BASE }, { MPC860_CIPR_SCC2, MPC860_SCC2_BASE }, { MPC860_CIPR_SCC3, MPC860_SCC3_BASE }, { MPC860_CIPR_SCC4, MPC860_SCC4_BASE },};/* Initialize SCC RX parameters */static void mpc860_scc_init_rx_params(struct mpc860_data *d,u_int scc_chan){ m_uint16_t scc_base,rbase; scc_base = scc_chan_info[scc_chan].dpram_base; /* Get the RBASE (offset 0) and store it in RBPTR */ rbase = dpram_r16(d,scc_base+0x00); dpram_w16(d,scc_base+0x10,rbase);}/* Initialize SCC TX parameters */static void mpc860_scc_init_tx_params(struct mpc860_data *d,u_int scc_chan){ m_uint16_t scc_base,tbase; scc_base = scc_chan_info[scc_chan].dpram_base; /* Get the TBASE (offset 2) and store it in TBPTR */ tbase = dpram_r16(d,scc_base+0x02); dpram_w16(d,scc_base+0x20,tbase);}/* Initialize SCC RX/TX parameters */static void mpc860_scc_init_rx_tx_params(struct mpc860_data *d,u_int scc_chan){ mpc860_scc_init_rx_params(d,scc_chan); mpc860_scc_init_tx_params(d,scc_chan);}/* Set an SCC interrupt */static int mpc860_scc_update_irq(struct mpc860_data *d,u_int scc_chan){ struct mpc860_scc_chan *chan = &d->scc_chan[scc_chan]; if (chan->scce & chan->sccm) d->cipr |= scc_chan_info[scc_chan].cipr_irq; else d->cipr &= ~scc_chan_info[scc_chan].cipr_irq; mpc860_update_cpm_int_status(d); return(0);}/* Fetch a SCC buffer descriptor */static int mpc860_scc_fetch_bd(struct mpc860_data *d,m_uint16_t bd_addr, struct mpc860_scc_bd *bd){ void *ptr; if ((bd_addr < MPC860_DPRAM_OFFSET) || (bd_addr > MPC860_DPRAM_END)) return(-1); bd->offset = bd_addr - MPC860_DPRAM_OFFSET; ptr = &d->dpram[bd->offset]; /* Fetch control word */ bd->ctrl = dpram_r16(d,bd->offset+0x00); /* Fetch buffer length and buffer pointer */ bd->buf_len = dpram_r16(d,bd->offset+0x02); bd->bp = dpram_r32(d,bd->offset+0x04);#if DEBUG_SCC MPC_LOG(d,"fetched SCC BD at 0x%4.4x, bp=0x%8.8x, len=%d\n", bd->offset,bd->bp,bd->buf_len);#endif return(0);}/* Handle the TX ring of an SCC channel (transmit a single packet) */static int mpc860_scc_handle_tx_ring_single(struct mpc860_data *d, u_int scc_chan){ struct mpc860_scc_bd txd0,ctxd,*ptxd; struct mpc860_scc_chan *chan; scc_chan_info_t *scc_info; m_uint16_t bd_offset; m_uint32_t clen,tot_len; u_char *pkt_ptr; int done = FALSE; int irq = FALSE; scc_info = &scc_chan_info[scc_chan]; chan = &d->scc_chan[scc_chan]; /* Get the TBPTR (offset 0x20) register */ bd_offset = dpram_r16(d,scc_info->dpram_base+0x20); /* Try to acquire the first descriptor */ ptxd = &txd0; mpc860_scc_fetch_bd(d,bd_offset,ptxd); /* If we don't own the first descriptor, we cannot transmit */ if (!(txd0.ctrl & MPC860_SCC_TXBD_CTRL_R)) return(FALSE); /* Empty packet for now */ pkt_ptr = chan->tx_pkt; tot_len = 0; do { /* Copy data into the buffer */ clen = ptxd->buf_len; physmem_copy_from_vm(d->vm,pkt_ptr,ptxd->bp,clen); pkt_ptr += clen; tot_len += clen; /* Signal IRQ ? */ if (ptxd->ctrl & MPC860_SCC_TXBD_CTRL_I) irq = TRUE; /* * Clear the ready bit (except for the first descriptor, * which is cleared when the full packet has been sent). */ if (ptxd != &txd0) { ptxd->ctrl &= ~MPC860_SCC_TXBD_CTRL_R; dpram_w16(d,ptxd->offset+0x00,ptxd->ctrl); } /* Set pointer on next TX descriptor (wrap ring if necessary) */ if (ptxd->ctrl & MPC860_SCC_TXBD_CTRL_W) { bd_offset = dpram_r16(d,scc_info->dpram_base+0x02); } else { bd_offset += MPC860_SCC_BD_SIZE; } dpram_w16(d,scc_info->dpram_base+0x20,bd_offset); /* If this is the last descriptor, we have finished */ if (!(ptxd->ctrl & MPC860_SCC_TXBD_CTRL_L)) { mpc860_scc_fetch_bd(d,bd_offset,&ctxd); ptxd = &ctxd; } else { done = TRUE; } }while(!done); if (tot_len != 0) {#if DEBUG_SCC MPC_LOG(d,"SCC%u: sending packet of %u bytes\n",scc_chan+1,tot_len); mem_dump(log_file,chan->tx_pkt,tot_len);#endif /* send packet on wire */ netio_send(chan->nio,chan->tx_pkt,tot_len); } /* Clear the Ready bit of the first TX descriptor */ txd0.ctrl &= ~MPC860_SCC_TXBD_CTRL_R; dpram_w16(d,txd0.offset+0x00,txd0.ctrl); /* Trigger SCC IRQ */ if (irq) { chan->scce |= MPC860_SCCE_TXB; mpc860_scc_update_irq(d,scc_chan); } return(TRUE);}/* Handle the TX ring of the specified SCC channel (multiple pkts possible) */static int mpc860_scc_handle_tx_ring(struct mpc860_data *d,u_int scc_chan){ int i; for(i=0;i<MPC860_TXRING_PASS_COUNT;i++) if (!mpc860_scc_handle_tx_ring_single(d,scc_chan)) break; return(TRUE);}/* Handle RX packet for an SCC channel */static int mpc860_scc_handle_rx_pkt(netio_desc_t *nio, u_char *pkt,ssize_t pkt_len, struct mpc860_data *d,void *arg){ struct mpc860_scc_bd rxd0,crxd,*prxd; struct mpc860_scc_chan *chan; u_int scc_chan = (int)arg;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -