18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Hitachi (now Renesas) SCA-II HD64572 driver for Linux 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1998-2008 Krzysztof Halasa <khc@pm.waw.pl> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Source of information: HD64572 SCA-II User's Manual 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * We use the following SCA memory map: 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Packet buffer descriptor rings - starting from card->rambase: 128c2ecf20Sopenharmony_ci * rx_ring_buffers * sizeof(pkt_desc) = logical channel #0 RX ring 138c2ecf20Sopenharmony_ci * tx_ring_buffers * sizeof(pkt_desc) = logical channel #0 TX ring 148c2ecf20Sopenharmony_ci * rx_ring_buffers * sizeof(pkt_desc) = logical channel #1 RX ring (if used) 158c2ecf20Sopenharmony_ci * tx_ring_buffers * sizeof(pkt_desc) = logical channel #1 TX ring (if used) 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * Packet data buffers - starting from card->rambase + buff_offset: 188c2ecf20Sopenharmony_ci * rx_ring_buffers * HDLC_MAX_MRU = logical channel #0 RX buffers 198c2ecf20Sopenharmony_ci * tx_ring_buffers * HDLC_MAX_MRU = logical channel #0 TX buffers 208c2ecf20Sopenharmony_ci * rx_ring_buffers * HDLC_MAX_MRU = logical channel #0 RX buffers (if used) 218c2ecf20Sopenharmony_ci * tx_ring_buffers * HDLC_MAX_MRU = logical channel #0 TX buffers (if used) 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <linux/bitops.h> 258c2ecf20Sopenharmony_ci#include <linux/errno.h> 268c2ecf20Sopenharmony_ci#include <linux/fcntl.h> 278c2ecf20Sopenharmony_ci#include <linux/hdlc.h> 288c2ecf20Sopenharmony_ci#include <linux/in.h> 298c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 308c2ecf20Sopenharmony_ci#include <linux/ioport.h> 318c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 328c2ecf20Sopenharmony_ci#include <linux/kernel.h> 338c2ecf20Sopenharmony_ci#include <linux/module.h> 348c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 358c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 368c2ecf20Sopenharmony_ci#include <linux/string.h> 378c2ecf20Sopenharmony_ci#include <linux/types.h> 388c2ecf20Sopenharmony_ci#include <asm/io.h> 398c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 408c2ecf20Sopenharmony_ci#include "hd64572.h" 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define NAPI_WEIGHT 16 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#define get_msci(port) (port->chan ? MSCI1_OFFSET : MSCI0_OFFSET) 458c2ecf20Sopenharmony_ci#define get_dmac_rx(port) (port->chan ? DMAC1RX_OFFSET : DMAC0RX_OFFSET) 468c2ecf20Sopenharmony_ci#define get_dmac_tx(port) (port->chan ? DMAC1TX_OFFSET : DMAC0TX_OFFSET) 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#define sca_in(reg, card) readb(card->scabase + (reg)) 498c2ecf20Sopenharmony_ci#define sca_out(value, reg, card) writeb(value, card->scabase + (reg)) 508c2ecf20Sopenharmony_ci#define sca_inw(reg, card) readw(card->scabase + (reg)) 518c2ecf20Sopenharmony_ci#define sca_outw(value, reg, card) writew(value, card->scabase + (reg)) 528c2ecf20Sopenharmony_ci#define sca_inl(reg, card) readl(card->scabase + (reg)) 538c2ecf20Sopenharmony_ci#define sca_outl(value, reg, card) writel(value, card->scabase + (reg)) 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic int sca_poll(struct napi_struct *napi, int budget); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic inline port_t* dev_to_port(struct net_device *dev) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci return dev_to_hdlc(dev)->priv; 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic inline void enable_intr(port_t *port) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci /* enable DMIB and MSCI RXINTA interrupts */ 658c2ecf20Sopenharmony_ci sca_outl(sca_inl(IER0, port->card) | 668c2ecf20Sopenharmony_ci (port->chan ? 0x08002200 : 0x00080022), IER0, port->card); 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic inline void disable_intr(port_t *port) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci sca_outl(sca_inl(IER0, port->card) & 728c2ecf20Sopenharmony_ci (port->chan ? 0x00FF00FF : 0xFF00FF00), IER0, port->card); 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic inline u16 desc_abs_number(port_t *port, u16 desc, int transmit) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci u16 rx_buffs = port->card->rx_ring_buffers; 788c2ecf20Sopenharmony_ci u16 tx_buffs = port->card->tx_ring_buffers; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci desc %= (transmit ? tx_buffs : rx_buffs); // called with "X + 1" etc. 818c2ecf20Sopenharmony_ci return port->chan * (rx_buffs + tx_buffs) + transmit * rx_buffs + desc; 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic inline u16 desc_offset(port_t *port, u16 desc, int transmit) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci /* Descriptor offset always fits in 16 bits */ 888c2ecf20Sopenharmony_ci return desc_abs_number(port, desc, transmit) * sizeof(pkt_desc); 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic inline pkt_desc __iomem *desc_address(port_t *port, u16 desc, 938c2ecf20Sopenharmony_ci int transmit) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci return (pkt_desc __iomem *)(port->card->rambase + 968c2ecf20Sopenharmony_ci desc_offset(port, desc, transmit)); 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic inline u32 buffer_offset(port_t *port, u16 desc, int transmit) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci return port->card->buff_offset + 1038c2ecf20Sopenharmony_ci desc_abs_number(port, desc, transmit) * (u32)HDLC_MAX_MRU; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic inline void sca_set_carrier(port_t *port) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci if (!(sca_in(get_msci(port) + ST3, port->card) & ST3_DCD)) { 1108c2ecf20Sopenharmony_ci#ifdef DEBUG_LINK 1118c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: sca_set_carrier on\n", 1128c2ecf20Sopenharmony_ci port->netdev.name); 1138c2ecf20Sopenharmony_ci#endif 1148c2ecf20Sopenharmony_ci netif_carrier_on(port->netdev); 1158c2ecf20Sopenharmony_ci } else { 1168c2ecf20Sopenharmony_ci#ifdef DEBUG_LINK 1178c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: sca_set_carrier off\n", 1188c2ecf20Sopenharmony_ci port->netdev.name); 1198c2ecf20Sopenharmony_ci#endif 1208c2ecf20Sopenharmony_ci netif_carrier_off(port->netdev); 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic void sca_init_port(port_t *port) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci card_t *card = port->card; 1288c2ecf20Sopenharmony_ci u16 dmac_rx = get_dmac_rx(port), dmac_tx = get_dmac_tx(port); 1298c2ecf20Sopenharmony_ci int transmit, i; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci port->rxin = 0; 1328c2ecf20Sopenharmony_ci port->txin = 0; 1338c2ecf20Sopenharmony_ci port->txlast = 0; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci for (transmit = 0; transmit < 2; transmit++) { 1368c2ecf20Sopenharmony_ci u16 buffs = transmit ? card->tx_ring_buffers 1378c2ecf20Sopenharmony_ci : card->rx_ring_buffers; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci for (i = 0; i < buffs; i++) { 1408c2ecf20Sopenharmony_ci pkt_desc __iomem *desc = desc_address(port, i, transmit); 1418c2ecf20Sopenharmony_ci u16 chain_off = desc_offset(port, i + 1, transmit); 1428c2ecf20Sopenharmony_ci u32 buff_off = buffer_offset(port, i, transmit); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci writel(chain_off, &desc->cp); 1458c2ecf20Sopenharmony_ci writel(buff_off, &desc->bp); 1468c2ecf20Sopenharmony_ci writew(0, &desc->len); 1478c2ecf20Sopenharmony_ci writeb(0, &desc->stat); 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci /* DMA disable - to halt state */ 1528c2ecf20Sopenharmony_ci sca_out(0, DSR_RX(port->chan), card); 1538c2ecf20Sopenharmony_ci sca_out(0, DSR_TX(port->chan), card); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci /* software ABORT - to initial state */ 1568c2ecf20Sopenharmony_ci sca_out(DCR_ABORT, DCR_RX(port->chan), card); 1578c2ecf20Sopenharmony_ci sca_out(DCR_ABORT, DCR_TX(port->chan), card); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci /* current desc addr */ 1608c2ecf20Sopenharmony_ci sca_outl(desc_offset(port, 0, 0), dmac_rx + CDAL, card); 1618c2ecf20Sopenharmony_ci sca_outl(desc_offset(port, card->tx_ring_buffers - 1, 0), 1628c2ecf20Sopenharmony_ci dmac_rx + EDAL, card); 1638c2ecf20Sopenharmony_ci sca_outl(desc_offset(port, 0, 1), dmac_tx + CDAL, card); 1648c2ecf20Sopenharmony_ci sca_outl(desc_offset(port, 0, 1), dmac_tx + EDAL, card); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci /* clear frame end interrupt counter */ 1678c2ecf20Sopenharmony_ci sca_out(DCR_CLEAR_EOF, DCR_RX(port->chan), card); 1688c2ecf20Sopenharmony_ci sca_out(DCR_CLEAR_EOF, DCR_TX(port->chan), card); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci /* Receive */ 1718c2ecf20Sopenharmony_ci sca_outw(HDLC_MAX_MRU, dmac_rx + BFLL, card); /* set buffer length */ 1728c2ecf20Sopenharmony_ci sca_out(0x14, DMR_RX(port->chan), card); /* Chain mode, Multi-frame */ 1738c2ecf20Sopenharmony_ci sca_out(DIR_EOME, DIR_RX(port->chan), card); /* enable interrupts */ 1748c2ecf20Sopenharmony_ci sca_out(DSR_DE, DSR_RX(port->chan), card); /* DMA enable */ 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci /* Transmit */ 1778c2ecf20Sopenharmony_ci sca_out(0x14, DMR_TX(port->chan), card); /* Chain mode, Multi-frame */ 1788c2ecf20Sopenharmony_ci sca_out(DIR_EOME, DIR_TX(port->chan), card); /* enable interrupts */ 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci sca_set_carrier(port); 1818c2ecf20Sopenharmony_ci netif_napi_add(port->netdev, &port->napi, sca_poll, NAPI_WEIGHT); 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci/* MSCI interrupt service */ 1868c2ecf20Sopenharmony_cistatic inline void sca_msci_intr(port_t *port) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci u16 msci = get_msci(port); 1898c2ecf20Sopenharmony_ci card_t* card = port->card; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci if (sca_in(msci + ST1, card) & ST1_CDCD) { 1928c2ecf20Sopenharmony_ci /* Reset MSCI CDCD status bit */ 1938c2ecf20Sopenharmony_ci sca_out(ST1_CDCD, msci + ST1, card); 1948c2ecf20Sopenharmony_ci sca_set_carrier(port); 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic inline void sca_rx(card_t *card, port_t *port, pkt_desc __iomem *desc, 2008c2ecf20Sopenharmony_ci u16 rxin) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci struct net_device *dev = port->netdev; 2038c2ecf20Sopenharmony_ci struct sk_buff *skb; 2048c2ecf20Sopenharmony_ci u16 len; 2058c2ecf20Sopenharmony_ci u32 buff; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci len = readw(&desc->len); 2088c2ecf20Sopenharmony_ci skb = dev_alloc_skb(len); 2098c2ecf20Sopenharmony_ci if (!skb) { 2108c2ecf20Sopenharmony_ci dev->stats.rx_dropped++; 2118c2ecf20Sopenharmony_ci return; 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci buff = buffer_offset(port, rxin, 0); 2158c2ecf20Sopenharmony_ci memcpy_fromio(skb->data, card->rambase + buff, len); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci skb_put(skb, len); 2188c2ecf20Sopenharmony_ci#ifdef DEBUG_PKT 2198c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s RX(%i):", dev->name, skb->len); 2208c2ecf20Sopenharmony_ci debug_frame(skb); 2218c2ecf20Sopenharmony_ci#endif 2228c2ecf20Sopenharmony_ci dev->stats.rx_packets++; 2238c2ecf20Sopenharmony_ci dev->stats.rx_bytes += skb->len; 2248c2ecf20Sopenharmony_ci skb->protocol = hdlc_type_trans(skb, dev); 2258c2ecf20Sopenharmony_ci netif_receive_skb(skb); 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci/* Receive DMA service */ 2308c2ecf20Sopenharmony_cistatic inline int sca_rx_done(port_t *port, int budget) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci struct net_device *dev = port->netdev; 2338c2ecf20Sopenharmony_ci u16 dmac = get_dmac_rx(port); 2348c2ecf20Sopenharmony_ci card_t *card = port->card; 2358c2ecf20Sopenharmony_ci u8 stat = sca_in(DSR_RX(port->chan), card); /* read DMA Status */ 2368c2ecf20Sopenharmony_ci int received = 0; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci /* Reset DSR status bits */ 2398c2ecf20Sopenharmony_ci sca_out((stat & (DSR_EOT | DSR_EOM | DSR_BOF | DSR_COF)) | DSR_DWE, 2408c2ecf20Sopenharmony_ci DSR_RX(port->chan), card); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (stat & DSR_BOF) 2438c2ecf20Sopenharmony_ci /* Dropped one or more frames */ 2448c2ecf20Sopenharmony_ci dev->stats.rx_over_errors++; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci while (received < budget) { 2478c2ecf20Sopenharmony_ci u32 desc_off = desc_offset(port, port->rxin, 0); 2488c2ecf20Sopenharmony_ci pkt_desc __iomem *desc; 2498c2ecf20Sopenharmony_ci u32 cda = sca_inl(dmac + CDAL, card); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if ((cda >= desc_off) && (cda < desc_off + sizeof(pkt_desc))) 2528c2ecf20Sopenharmony_ci break; /* No frame received */ 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci desc = desc_address(port, port->rxin, 0); 2558c2ecf20Sopenharmony_ci stat = readb(&desc->stat); 2568c2ecf20Sopenharmony_ci if (!(stat & ST_RX_EOM)) 2578c2ecf20Sopenharmony_ci port->rxpart = 1; /* partial frame received */ 2588c2ecf20Sopenharmony_ci else if ((stat & ST_ERROR_MASK) || port->rxpart) { 2598c2ecf20Sopenharmony_ci dev->stats.rx_errors++; 2608c2ecf20Sopenharmony_ci if (stat & ST_RX_OVERRUN) 2618c2ecf20Sopenharmony_ci dev->stats.rx_fifo_errors++; 2628c2ecf20Sopenharmony_ci else if ((stat & (ST_RX_SHORT | ST_RX_ABORT | 2638c2ecf20Sopenharmony_ci ST_RX_RESBIT)) || port->rxpart) 2648c2ecf20Sopenharmony_ci dev->stats.rx_frame_errors++; 2658c2ecf20Sopenharmony_ci else if (stat & ST_RX_CRC) 2668c2ecf20Sopenharmony_ci dev->stats.rx_crc_errors++; 2678c2ecf20Sopenharmony_ci if (stat & ST_RX_EOM) 2688c2ecf20Sopenharmony_ci port->rxpart = 0; /* received last fragment */ 2698c2ecf20Sopenharmony_ci } else { 2708c2ecf20Sopenharmony_ci sca_rx(card, port, desc, port->rxin); 2718c2ecf20Sopenharmony_ci received++; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci /* Set new error descriptor address */ 2758c2ecf20Sopenharmony_ci sca_outl(desc_off, dmac + EDAL, card); 2768c2ecf20Sopenharmony_ci port->rxin = (port->rxin + 1) % card->rx_ring_buffers; 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci /* make sure RX DMA is enabled */ 2808c2ecf20Sopenharmony_ci sca_out(DSR_DE, DSR_RX(port->chan), card); 2818c2ecf20Sopenharmony_ci return received; 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci/* Transmit DMA service */ 2868c2ecf20Sopenharmony_cistatic inline void sca_tx_done(port_t *port) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci struct net_device *dev = port->netdev; 2898c2ecf20Sopenharmony_ci card_t* card = port->card; 2908c2ecf20Sopenharmony_ci u8 stat; 2918c2ecf20Sopenharmony_ci unsigned count = 0; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci spin_lock(&port->lock); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci stat = sca_in(DSR_TX(port->chan), card); /* read DMA Status */ 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci /* Reset DSR status bits */ 2988c2ecf20Sopenharmony_ci sca_out((stat & (DSR_EOT | DSR_EOM | DSR_BOF | DSR_COF)) | DSR_DWE, 2998c2ecf20Sopenharmony_ci DSR_TX(port->chan), card); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci while (1) { 3028c2ecf20Sopenharmony_ci pkt_desc __iomem *desc = desc_address(port, port->txlast, 1); 3038c2ecf20Sopenharmony_ci u8 stat = readb(&desc->stat); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci if (!(stat & ST_TX_OWNRSHP)) 3068c2ecf20Sopenharmony_ci break; /* not yet transmitted */ 3078c2ecf20Sopenharmony_ci if (stat & ST_TX_UNDRRUN) { 3088c2ecf20Sopenharmony_ci dev->stats.tx_errors++; 3098c2ecf20Sopenharmony_ci dev->stats.tx_fifo_errors++; 3108c2ecf20Sopenharmony_ci } else { 3118c2ecf20Sopenharmony_ci dev->stats.tx_packets++; 3128c2ecf20Sopenharmony_ci dev->stats.tx_bytes += readw(&desc->len); 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci writeb(0, &desc->stat); /* Free descriptor */ 3158c2ecf20Sopenharmony_ci count++; 3168c2ecf20Sopenharmony_ci port->txlast = (port->txlast + 1) % card->tx_ring_buffers; 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci if (count) 3208c2ecf20Sopenharmony_ci netif_wake_queue(dev); 3218c2ecf20Sopenharmony_ci spin_unlock(&port->lock); 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic int sca_poll(struct napi_struct *napi, int budget) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci port_t *port = container_of(napi, port_t, napi); 3288c2ecf20Sopenharmony_ci u32 isr0 = sca_inl(ISR0, port->card); 3298c2ecf20Sopenharmony_ci int received = 0; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci if (isr0 & (port->chan ? 0x08000000 : 0x00080000)) 3328c2ecf20Sopenharmony_ci sca_msci_intr(port); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (isr0 & (port->chan ? 0x00002000 : 0x00000020)) 3358c2ecf20Sopenharmony_ci sca_tx_done(port); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci if (isr0 & (port->chan ? 0x00000200 : 0x00000002)) 3388c2ecf20Sopenharmony_ci received = sca_rx_done(port, budget); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci if (received < budget) { 3418c2ecf20Sopenharmony_ci napi_complete_done(napi, received); 3428c2ecf20Sopenharmony_ci enable_intr(port); 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci return received; 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistatic irqreturn_t sca_intr(int irq, void *dev_id) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci card_t *card = dev_id; 3518c2ecf20Sopenharmony_ci u32 isr0 = sca_inl(ISR0, card); 3528c2ecf20Sopenharmony_ci int i, handled = 0; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 3558c2ecf20Sopenharmony_ci port_t *port = get_port(card, i); 3568c2ecf20Sopenharmony_ci if (port && (isr0 & (i ? 0x08002200 : 0x00080022))) { 3578c2ecf20Sopenharmony_ci handled = 1; 3588c2ecf20Sopenharmony_ci disable_intr(port); 3598c2ecf20Sopenharmony_ci napi_schedule(&port->napi); 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci return IRQ_RETVAL(handled); 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_cistatic void sca_set_port(port_t *port) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci card_t* card = port->card; 3708c2ecf20Sopenharmony_ci u16 msci = get_msci(port); 3718c2ecf20Sopenharmony_ci u8 md2 = sca_in(msci + MD2, card); 3728c2ecf20Sopenharmony_ci unsigned int tmc, br = 10, brv = 1024; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci if (port->settings.clock_rate > 0) { 3768c2ecf20Sopenharmony_ci /* Try lower br for better accuracy*/ 3778c2ecf20Sopenharmony_ci do { 3788c2ecf20Sopenharmony_ci br--; 3798c2ecf20Sopenharmony_ci brv >>= 1; /* brv = 2^9 = 512 max in specs */ 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci /* Baud Rate = CLOCK_BASE / TMC / 2^BR */ 3828c2ecf20Sopenharmony_ci tmc = CLOCK_BASE / brv / port->settings.clock_rate; 3838c2ecf20Sopenharmony_ci }while (br > 1 && tmc <= 128); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci if (tmc < 1) { 3868c2ecf20Sopenharmony_ci tmc = 1; 3878c2ecf20Sopenharmony_ci br = 0; /* For baud=CLOCK_BASE we use tmc=1 br=0 */ 3888c2ecf20Sopenharmony_ci brv = 1; 3898c2ecf20Sopenharmony_ci } else if (tmc > 255) 3908c2ecf20Sopenharmony_ci tmc = 256; /* tmc=0 means 256 - low baud rates */ 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci port->settings.clock_rate = CLOCK_BASE / brv / tmc; 3938c2ecf20Sopenharmony_ci } else { 3948c2ecf20Sopenharmony_ci br = 9; /* Minimum clock rate */ 3958c2ecf20Sopenharmony_ci tmc = 256; /* 8bit = 0 */ 3968c2ecf20Sopenharmony_ci port->settings.clock_rate = CLOCK_BASE / (256 * 512); 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci port->rxs = (port->rxs & ~CLK_BRG_MASK) | br; 4008c2ecf20Sopenharmony_ci port->txs = (port->txs & ~CLK_BRG_MASK) | br; 4018c2ecf20Sopenharmony_ci port->tmc = tmc; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci /* baud divisor - time constant*/ 4048c2ecf20Sopenharmony_ci sca_out(port->tmc, msci + TMCR, card); 4058c2ecf20Sopenharmony_ci sca_out(port->tmc, msci + TMCT, card); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci /* Set BRG bits */ 4088c2ecf20Sopenharmony_ci sca_out(port->rxs, msci + RXS, card); 4098c2ecf20Sopenharmony_ci sca_out(port->txs, msci + TXS, card); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (port->settings.loopback) 4128c2ecf20Sopenharmony_ci md2 |= MD2_LOOPBACK; 4138c2ecf20Sopenharmony_ci else 4148c2ecf20Sopenharmony_ci md2 &= ~MD2_LOOPBACK; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci sca_out(md2, msci + MD2, card); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic void sca_open(struct net_device *dev) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci port_t *port = dev_to_port(dev); 4248c2ecf20Sopenharmony_ci card_t* card = port->card; 4258c2ecf20Sopenharmony_ci u16 msci = get_msci(port); 4268c2ecf20Sopenharmony_ci u8 md0, md2; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci switch(port->encoding) { 4298c2ecf20Sopenharmony_ci case ENCODING_NRZ: md2 = MD2_NRZ; break; 4308c2ecf20Sopenharmony_ci case ENCODING_NRZI: md2 = MD2_NRZI; break; 4318c2ecf20Sopenharmony_ci case ENCODING_FM_MARK: md2 = MD2_FM_MARK; break; 4328c2ecf20Sopenharmony_ci case ENCODING_FM_SPACE: md2 = MD2_FM_SPACE; break; 4338c2ecf20Sopenharmony_ci default: md2 = MD2_MANCHESTER; 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci if (port->settings.loopback) 4378c2ecf20Sopenharmony_ci md2 |= MD2_LOOPBACK; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci switch(port->parity) { 4408c2ecf20Sopenharmony_ci case PARITY_CRC16_PR0: md0 = MD0_HDLC | MD0_CRC_16_0; break; 4418c2ecf20Sopenharmony_ci case PARITY_CRC16_PR1: md0 = MD0_HDLC | MD0_CRC_16; break; 4428c2ecf20Sopenharmony_ci case PARITY_CRC32_PR1_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU32; break; 4438c2ecf20Sopenharmony_ci case PARITY_CRC16_PR1_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU; break; 4448c2ecf20Sopenharmony_ci default: md0 = MD0_HDLC | MD0_CRC_NONE; 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci sca_out(CMD_RESET, msci + CMD, card); 4488c2ecf20Sopenharmony_ci sca_out(md0, msci + MD0, card); 4498c2ecf20Sopenharmony_ci sca_out(0x00, msci + MD1, card); /* no address field check */ 4508c2ecf20Sopenharmony_ci sca_out(md2, msci + MD2, card); 4518c2ecf20Sopenharmony_ci sca_out(0x7E, msci + IDL, card); /* flag character 0x7E */ 4528c2ecf20Sopenharmony_ci /* Skip the rest of underrun frame */ 4538c2ecf20Sopenharmony_ci sca_out(CTL_IDLE | CTL_URCT | CTL_URSKP, msci + CTL, card); 4548c2ecf20Sopenharmony_ci sca_out(0x0F, msci + RNR, card); /* +1=RX DMA activation condition */ 4558c2ecf20Sopenharmony_ci sca_out(0x3C, msci + TFS, card); /* +1 = TX start */ 4568c2ecf20Sopenharmony_ci sca_out(0x38, msci + TCR, card); /* =Critical TX DMA activ condition */ 4578c2ecf20Sopenharmony_ci sca_out(0x38, msci + TNR0, card); /* =TX DMA activation condition */ 4588c2ecf20Sopenharmony_ci sca_out(0x3F, msci + TNR1, card); /* +1=TX DMA deactivation condition*/ 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci/* We're using the following interrupts: 4618c2ecf20Sopenharmony_ci - RXINTA (DCD changes only) 4628c2ecf20Sopenharmony_ci - DMIB (EOM - single frame transfer complete) 4638c2ecf20Sopenharmony_ci*/ 4648c2ecf20Sopenharmony_ci sca_outl(IE0_RXINTA | IE0_CDCD, msci + IE0, card); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci sca_out(port->tmc, msci + TMCR, card); 4678c2ecf20Sopenharmony_ci sca_out(port->tmc, msci + TMCT, card); 4688c2ecf20Sopenharmony_ci sca_out(port->rxs, msci + RXS, card); 4698c2ecf20Sopenharmony_ci sca_out(port->txs, msci + TXS, card); 4708c2ecf20Sopenharmony_ci sca_out(CMD_TX_ENABLE, msci + CMD, card); 4718c2ecf20Sopenharmony_ci sca_out(CMD_RX_ENABLE, msci + CMD, card); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci sca_set_carrier(port); 4748c2ecf20Sopenharmony_ci enable_intr(port); 4758c2ecf20Sopenharmony_ci napi_enable(&port->napi); 4768c2ecf20Sopenharmony_ci netif_start_queue(dev); 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_cistatic void sca_close(struct net_device *dev) 4818c2ecf20Sopenharmony_ci{ 4828c2ecf20Sopenharmony_ci port_t *port = dev_to_port(dev); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci /* reset channel */ 4858c2ecf20Sopenharmony_ci sca_out(CMD_RESET, get_msci(port) + CMD, port->card); 4868c2ecf20Sopenharmony_ci disable_intr(port); 4878c2ecf20Sopenharmony_ci napi_disable(&port->napi); 4888c2ecf20Sopenharmony_ci netif_stop_queue(dev); 4898c2ecf20Sopenharmony_ci} 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_cistatic int sca_attach(struct net_device *dev, unsigned short encoding, 4938c2ecf20Sopenharmony_ci unsigned short parity) 4948c2ecf20Sopenharmony_ci{ 4958c2ecf20Sopenharmony_ci if (encoding != ENCODING_NRZ && 4968c2ecf20Sopenharmony_ci encoding != ENCODING_NRZI && 4978c2ecf20Sopenharmony_ci encoding != ENCODING_FM_MARK && 4988c2ecf20Sopenharmony_ci encoding != ENCODING_FM_SPACE && 4998c2ecf20Sopenharmony_ci encoding != ENCODING_MANCHESTER) 5008c2ecf20Sopenharmony_ci return -EINVAL; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci if (parity != PARITY_NONE && 5038c2ecf20Sopenharmony_ci parity != PARITY_CRC16_PR0 && 5048c2ecf20Sopenharmony_ci parity != PARITY_CRC16_PR1 && 5058c2ecf20Sopenharmony_ci parity != PARITY_CRC32_PR1_CCITT && 5068c2ecf20Sopenharmony_ci parity != PARITY_CRC16_PR1_CCITT) 5078c2ecf20Sopenharmony_ci return -EINVAL; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci dev_to_port(dev)->encoding = encoding; 5108c2ecf20Sopenharmony_ci dev_to_port(dev)->parity = parity; 5118c2ecf20Sopenharmony_ci return 0; 5128c2ecf20Sopenharmony_ci} 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci#ifdef DEBUG_RINGS 5168c2ecf20Sopenharmony_cistatic void sca_dump_rings(struct net_device *dev) 5178c2ecf20Sopenharmony_ci{ 5188c2ecf20Sopenharmony_ci port_t *port = dev_to_port(dev); 5198c2ecf20Sopenharmony_ci card_t *card = port->card; 5208c2ecf20Sopenharmony_ci u16 cnt; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci printk(KERN_DEBUG "RX ring: CDA=%u EDA=%u DSR=%02X in=%u %sactive", 5238c2ecf20Sopenharmony_ci sca_inl(get_dmac_rx(port) + CDAL, card), 5248c2ecf20Sopenharmony_ci sca_inl(get_dmac_rx(port) + EDAL, card), 5258c2ecf20Sopenharmony_ci sca_in(DSR_RX(port->chan), card), port->rxin, 5268c2ecf20Sopenharmony_ci sca_in(DSR_RX(port->chan), card) & DSR_DE ? "" : "in"); 5278c2ecf20Sopenharmony_ci for (cnt = 0; cnt < port->card->rx_ring_buffers; cnt++) 5288c2ecf20Sopenharmony_ci pr_cont(" %02X", readb(&(desc_address(port, cnt, 0)->stat))); 5298c2ecf20Sopenharmony_ci pr_cont("\n"); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci printk(KERN_DEBUG "TX ring: CDA=%u EDA=%u DSR=%02X in=%u " 5328c2ecf20Sopenharmony_ci "last=%u %sactive", 5338c2ecf20Sopenharmony_ci sca_inl(get_dmac_tx(port) + CDAL, card), 5348c2ecf20Sopenharmony_ci sca_inl(get_dmac_tx(port) + EDAL, card), 5358c2ecf20Sopenharmony_ci sca_in(DSR_TX(port->chan), card), port->txin, port->txlast, 5368c2ecf20Sopenharmony_ci sca_in(DSR_TX(port->chan), card) & DSR_DE ? "" : "in"); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci for (cnt = 0; cnt < port->card->tx_ring_buffers; cnt++) 5398c2ecf20Sopenharmony_ci pr_cont(" %02X", readb(&(desc_address(port, cnt, 1)->stat))); 5408c2ecf20Sopenharmony_ci pr_cont("\n"); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci printk(KERN_DEBUG "MSCI: MD: %02x %02x %02x," 5438c2ecf20Sopenharmony_ci " ST: %02x %02x %02x %02x %02x, FST: %02x CST: %02x %02x\n", 5448c2ecf20Sopenharmony_ci sca_in(get_msci(port) + MD0, card), 5458c2ecf20Sopenharmony_ci sca_in(get_msci(port) + MD1, card), 5468c2ecf20Sopenharmony_ci sca_in(get_msci(port) + MD2, card), 5478c2ecf20Sopenharmony_ci sca_in(get_msci(port) + ST0, card), 5488c2ecf20Sopenharmony_ci sca_in(get_msci(port) + ST1, card), 5498c2ecf20Sopenharmony_ci sca_in(get_msci(port) + ST2, card), 5508c2ecf20Sopenharmony_ci sca_in(get_msci(port) + ST3, card), 5518c2ecf20Sopenharmony_ci sca_in(get_msci(port) + ST4, card), 5528c2ecf20Sopenharmony_ci sca_in(get_msci(port) + FST, card), 5538c2ecf20Sopenharmony_ci sca_in(get_msci(port) + CST0, card), 5548c2ecf20Sopenharmony_ci sca_in(get_msci(port) + CST1, card)); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci printk(KERN_DEBUG "ILAR: %02x ISR: %08x %08x\n", sca_in(ILAR, card), 5578c2ecf20Sopenharmony_ci sca_inl(ISR0, card), sca_inl(ISR1, card)); 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci#endif /* DEBUG_RINGS */ 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_cistatic netdev_tx_t sca_xmit(struct sk_buff *skb, struct net_device *dev) 5638c2ecf20Sopenharmony_ci{ 5648c2ecf20Sopenharmony_ci port_t *port = dev_to_port(dev); 5658c2ecf20Sopenharmony_ci card_t *card = port->card; 5668c2ecf20Sopenharmony_ci pkt_desc __iomem *desc; 5678c2ecf20Sopenharmony_ci u32 buff, len; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci spin_lock_irq(&port->lock); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci desc = desc_address(port, port->txin + 1, 1); 5728c2ecf20Sopenharmony_ci BUG_ON(readb(&desc->stat)); /* previous xmit should stop queue */ 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci#ifdef DEBUG_PKT 5758c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s TX(%i):", dev->name, skb->len); 5768c2ecf20Sopenharmony_ci debug_frame(skb); 5778c2ecf20Sopenharmony_ci#endif 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci desc = desc_address(port, port->txin, 1); 5808c2ecf20Sopenharmony_ci buff = buffer_offset(port, port->txin, 1); 5818c2ecf20Sopenharmony_ci len = skb->len; 5828c2ecf20Sopenharmony_ci memcpy_toio(card->rambase + buff, skb->data, len); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci writew(len, &desc->len); 5858c2ecf20Sopenharmony_ci writeb(ST_TX_EOM, &desc->stat); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci port->txin = (port->txin + 1) % card->tx_ring_buffers; 5888c2ecf20Sopenharmony_ci sca_outl(desc_offset(port, port->txin, 1), 5898c2ecf20Sopenharmony_ci get_dmac_tx(port) + EDAL, card); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci sca_out(DSR_DE, DSR_TX(port->chan), card); /* Enable TX DMA */ 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci desc = desc_address(port, port->txin + 1, 1); 5948c2ecf20Sopenharmony_ci if (readb(&desc->stat)) /* allow 1 packet gap */ 5958c2ecf20Sopenharmony_ci netif_stop_queue(dev); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci spin_unlock_irq(&port->lock); 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 6008c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 6018c2ecf20Sopenharmony_ci} 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_cistatic u32 sca_detect_ram(card_t *card, u8 __iomem *rambase, u32 ramsize) 6058c2ecf20Sopenharmony_ci{ 6068c2ecf20Sopenharmony_ci /* Round RAM size to 32 bits, fill from end to start */ 6078c2ecf20Sopenharmony_ci u32 i = ramsize &= ~3; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci do { 6108c2ecf20Sopenharmony_ci i -= 4; 6118c2ecf20Sopenharmony_ci writel(i ^ 0x12345678, rambase + i); 6128c2ecf20Sopenharmony_ci } while (i > 0); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci for (i = 0; i < ramsize ; i += 4) { 6158c2ecf20Sopenharmony_ci if (readl(rambase + i) != (i ^ 0x12345678)) 6168c2ecf20Sopenharmony_ci break; 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci return i; 6208c2ecf20Sopenharmony_ci} 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_cistatic void sca_init(card_t *card, int wait_states) 6248c2ecf20Sopenharmony_ci{ 6258c2ecf20Sopenharmony_ci sca_out(wait_states, WCRL, card); /* Wait Control */ 6268c2ecf20Sopenharmony_ci sca_out(wait_states, WCRM, card); 6278c2ecf20Sopenharmony_ci sca_out(wait_states, WCRH, card); 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci sca_out(0, DMER, card); /* DMA Master disable */ 6308c2ecf20Sopenharmony_ci sca_out(0x03, PCR, card); /* DMA priority */ 6318c2ecf20Sopenharmony_ci sca_out(0, DSR_RX(0), card); /* DMA disable - to halt state */ 6328c2ecf20Sopenharmony_ci sca_out(0, DSR_TX(0), card); 6338c2ecf20Sopenharmony_ci sca_out(0, DSR_RX(1), card); 6348c2ecf20Sopenharmony_ci sca_out(0, DSR_TX(1), card); 6358c2ecf20Sopenharmony_ci sca_out(DMER_DME, DMER, card); /* DMA Master enable */ 6368c2ecf20Sopenharmony_ci} 637