The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/ppc/uartsmc.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 #include "u.h"
    2 #include "../port/lib.h"
    3 #include "mem.h"
    4 #include "dat.h"
    5 #include "fns.h"
    6 #include "io.h"
    7 #include "imm.h"
    8 #include "../port/error.h"
    9 #include "../ppc/uartsmc.h"
   10 
   11 /*
   12  * PowerPC 8260 SMC UART
   13  */
   14 
   15 enum {
   16         /* SMC Mode Registers */
   17         Clen            = 0x7800,       /* Character length */
   18         Sl              = 0x0400,       /* Stop length, 0: one stop bit, 1: two */
   19         Pen             = 0x0200,       /* Parity enable */
   20         Pm              = 0x0100,       /* Parity mode, 0 is odd */
   21         Sm              = 0x0030,       /* SMC mode, two bits */
   22         SMUart  = 0x0020,       /* SMC mode, 0b10 is uart */
   23         Dm              = 0x000c,       /* Diagnostic mode, 00 is normal */
   24         Ten             = 0x0002,       /* Transmit enable, 1 is enabled */
   25         Ren             = 0x0001,       /* Receive enable, 1 is enabled */
   26 
   27         /* SMC Event/Mask Registers */
   28         ce_Brke = 0x0040,       /* Break end */
   29         ce_Br   = 0x0020,       /* Break character received */
   30         ce_Bsy  = 0x0004,       /* Busy condition */
   31         ce_Txb  = 0x0002,       /* Tx buffer */
   32         ce_Rxb  = 0x0001,       /* Rx buffer */
   33 
   34         /* Receive/Transmit Buffer Descriptor Control bits */
   35         BDContin=       1<<9,
   36         BDIdle=         1<<8,
   37         BDPreamble=     1<<8,
   38         BDBreak=        1<<5,
   39         BDFrame=        1<<4,
   40         BDParity=       1<<3,
   41         BDOverrun=      1<<1,
   42 
   43         /* Tx and Rx buffer sizes (32 bytes) */
   44         Rxsize=         CACHELINESZ,
   45         Txsize=         CACHELINESZ,
   46 };
   47 
   48 extern PhysUart smcphysuart;
   49 
   50 Uart smcuart[Nuart] = {
   51         {
   52                 .name = "SMC1",
   53                 .baud = 115200,
   54                 .bits = 8,
   55                 .stop = 1,
   56                 .parity = 'n',
   57                 .phys = &smcphysuart,
   58                 .special = 0,
   59         },
   60 /*      Only configure SMC1 for now
   61         {
   62                 .name = "SMC2",
   63                 .baud = 115200,
   64                 .bits = 8,
   65                 .stop = 1,
   66                 .parity = 'n',
   67                 .phys = &smcphysuart,
   68                 .special = 0,
   69         },
   70 */
   71 };
   72 
   73 int uartinited = 0;
   74 
   75 static void smcinterrupt(Ureg*, void*);
   76 static void smcputc(Uart *uart, int c);
   77 
   78 int
   79 baudgen(int baud)
   80 {
   81         int d;
   82 
   83         d = ((m->brghz+(baud>>1))/baud)>>4;
   84         if(d >= (1<<12))
   85                 return ((d+15)>>3)|1;
   86         return d<<1;
   87 }
   88 
   89 static Uart*
   90 smcpnp(void)
   91 {
   92         int i;
   93 
   94         for (i = 0; i < nelem(smcuart) - 1; i++)
   95                 smcuart[i].next = smcuart + i + 1;
   96         return smcuart;
   97 }
   98 
   99 void
  100 smcinit(Uart *uart)
  101 {
  102         Uartsmc *p;
  103         SMC *smc;
  104         UartData *ud;
  105         ulong lcr;
  106         int bits;
  107 
  108         ud = uart->regs;
  109 
  110         if (ud->initialized)
  111                 return;
  112 
  113         smcsetup(uart); /* Steps 1 through 4, PPC-dependent */
  114         p = ud->usmc;
  115         smc = ud->smc;
  116 
  117         /* step 5: set up buffer descriptors */
  118         /* setup my uart structure */
  119         if (ud->rxb == nil)
  120                 ud->rxb = bdalloc(1);
  121         if (ud->txb == nil)
  122                 ud->txb = bdalloc(1);
  123 
  124         p->rbase = ((ulong)ud->rxb) - (ulong)IMMR;
  125         p->tbase = ((ulong)ud->txb) - (ulong)IMMR;
  126 
  127         /* step 8: receive buffer size */
  128         p->mrblr = Rxsize;
  129 
  130         /* step 9: */
  131         p->maxidl = 15;
  132 
  133         /* step 10: */
  134         p->brkln = 0;
  135         p->brkec = 0;
  136 
  137         /* step 11: */
  138         p->brkcr = 0;
  139 
  140         /* step 12: setup receive buffer */
  141         ud->rxb->status = BDEmpty|BDWrap|BDInt;
  142         ud->rxb->length = 0;
  143         ud->rxbuf = xspanalloc(Rxsize, 0, CACHELINESZ);
  144         ud->rxb->addr = PADDR(ud->rxbuf);
  145 
  146         /* step 13: step transmit buffer */
  147         ud->txb->status = BDWrap|BDInt;
  148         ud->txb->length = 0;
  149         ud->txbuf = xspanalloc(Txsize, 0, CACHELINESZ);
  150         ud->txb->addr = PADDR(ud->txbuf);
  151 
  152         /* step 14: clear events */
  153         smc->smce = ce_Brke | ce_Br | ce_Bsy | ce_Txb | ce_Rxb;
  154 
  155         /* 
  156          * step 15: enable interrupts (done later)
  157          * smc->smcm = ce_Brke | ce_Br | ce_Bsy | ce_Txb | ce_Rxb;
  158          */
  159 
  160         /* step 17: set parity, no of bits, UART mode, ... */
  161         lcr = SMUart;
  162         bits = uart->bits + 1;
  163 
  164         switch(uart->parity){
  165         case 'e':
  166                 lcr |= (Pen|Pm);
  167                 bits +=1;
  168                 break;
  169         case 'o':
  170                 lcr |= Pen;
  171                 bits +=1;
  172                 break;
  173         case 'n':
  174         default:
  175                 break;
  176         }
  177 
  178         if(uart->stop == 2){
  179                 lcr |= Sl;
  180                 bits += 1;
  181         }
  182 
  183         /* Set new value and reenable if device was previously enabled */
  184         smc->smcmr = lcr |  bits <<11 | 0x3;
  185 
  186         ud->initialized = 1;
  187 }
  188 
  189 static void
  190 smcenable(Uart *uart, int intenb)
  191 {
  192         UartData *ud;
  193         SMC *smc;
  194         int nr;
  195 
  196         nr = uart - smcuart;
  197         if (nr < 0 || nr > Nuart)
  198                 panic("No SMC %d", nr);
  199         ud = uartdata + nr;
  200         ud->smcno = nr;
  201         uart->regs = ud;
  202         if (ud->initialized == 0)
  203                 smcinit(uart);
  204         if (ud->enabled || intenb == 0)
  205                 return;
  206         smc = ud->smc;
  207         /* clear events */
  208         smc->smce = ce_Brke | ce_Br | ce_Bsy | ce_Txb | ce_Rxb;
  209         /* enable interrupts */
  210         smc->smcm = ce_Brke | ce_Br | ce_Bsy | ce_Txb | ce_Rxb;
  211         intrenable(VecSMC1 + ud->smcno, smcinterrupt, uart, uart->name);
  212         ud->enabled = 1;
  213 }
  214 
  215 static long
  216 smcstatus(Uart* uart, void* buf, long n, long offset)
  217 {
  218         SMC *sp;
  219         char p[128];
  220 
  221         sp = ((UartData*)uart->regs)->smc;
  222         snprint(p, sizeof p, "b%d c%d e%d l%d m0 p%c s%d i1\n"
  223                 "dev(%d) type(%d) framing(%d) overruns(%d)\n",
  224 
  225                 uart->baud,
  226                 uart->hup_dcd, 
  227                 uart->hup_dsr,
  228                 ((sp->smcmr & Clen) >>11) - ((sp->smcmr&Pen) ? 1 : 0) - ((sp->smcmr&Sl) ? 2 : 1),
  229                 (sp->smcmr & Pen) ? ((sp->smcmr & Pm) ? 'e': 'o'): 'n',
  230                 (sp->smcmr & Sl) ? 2: 1,
  231 
  232                 uart->dev,
  233                 uart->type,
  234                 uart->ferr,
  235                 uart->oerr 
  236         );
  237         n = readstr(offset, buf, n, p);
  238         free(p);
  239 
  240         return n;
  241 }
  242 
  243 static void
  244 smcfifo(Uart*, int)
  245 {
  246         /*
  247          * Toggle FIFOs:
  248          * if none, do nothing;
  249          * reset the Rx and Tx FIFOs;
  250          * empty the Rx buffer and clear any interrupt conditions;
  251          * if enabling, try to turn them on.
  252          */
  253         return;
  254 }
  255 
  256 static void
  257 smcdtr(Uart*, int)
  258 {
  259 }
  260 
  261 static void
  262 smcrts(Uart*, int)
  263 {
  264 }
  265 
  266 static void
  267 smcmodemctl(Uart*, int)
  268 {
  269 }
  270 
  271 static int
  272 smcparity(Uart* uart, int parity)
  273 {
  274         int lcr;
  275         SMC *sp;
  276 
  277         sp = ((UartData*)uart->regs)->smc;
  278 
  279         lcr = sp->smcmr & ~(Pen|Pm);
  280 
  281         /* Disable transmitter/receiver. */
  282         sp->smcmr &= ~(Ren | Ten);
  283 
  284         switch(parity){
  285         case 'e':
  286                 lcr |= (Pen|Pm);
  287                 break;
  288         case 'o':
  289                 lcr |= Pen;
  290                 break;
  291         case 'n':
  292         default:
  293                 break;
  294         }
  295         /* Set new value and reenable if device was previously enabled */
  296         sp->smcmr = lcr;
  297 
  298         uart->parity = parity;
  299 
  300         return 0;
  301 }
  302 
  303 static int
  304 smcstop(Uart* uart, int stop)
  305 {
  306         int lcr, bits;
  307         SMC *sp;
  308 
  309         sp = ((UartData*)uart->regs)->smc;
  310         lcr = sp->smcmr & ~(Sl | Clen);
  311 
  312         /* Disable transmitter/receiver. */
  313         sp->smcmr &= ~(Ren | Ten);
  314 
  315         switch(stop){
  316         case 1:
  317                 break;
  318         case 2:
  319                 lcr |= Sl;
  320                 break;
  321         default:
  322                 return -1;
  323         }
  324 
  325         bits = uart->bits + ((lcr & Pen) ? 1 : 0) + ((lcr & Sl) ? 2 : 1);
  326         lcr |= bits<<11;
  327 
  328         /* Set new value and reenable if device was previously enabled */
  329         sp->smcmr = lcr;
  330 
  331         uart->stop = stop;
  332 
  333         return 0;
  334 }
  335 
  336 static int
  337 smcbits(Uart* uart, int bits)
  338 {
  339         int lcr, b;
  340         SMC *sp;
  341 
  342         if (bits < 5 || bits > 14)
  343                 return -1;
  344 
  345         sp = ((UartData*)uart->regs)->smc;
  346         lcr = sp->smcmr & ~Clen;
  347 
  348         b = bits + ((sp->smcmr & Pen) ? 1 : 0) + ((sp->smcmr & Sl) ? 2 : 1);
  349 
  350         if (b > 15)
  351                 return -1;
  352 
  353         /* Disable transmitter/receiver */
  354         sp->smcmr &= ~(Ren | Ten);
  355 
  356         /* Set new value and reenable if device was previously enabled */
  357         sp->smcmr = lcr |  b<<11;
  358 
  359         uart->bits = bits;
  360 
  361         return 0;
  362 }
  363 
  364 static int
  365 smcbaud(Uart* uart, int baud)
  366 {
  367         int i;
  368         SMC *sp;
  369 
  370         if (uart->enabled){
  371                 sp = ((UartData*)uart->regs)->smc;
  372         
  373                 if(uart->freq == 0 || baud <= 0)
  374                         return -1;
  375         
  376                 i = sp - imm->smc;
  377                 imm->brgc[i] = (((m->brghz >> 4) / baud) << 1) | 0x00010000;
  378         }
  379         uart->baud = baud;
  380 
  381         return 0;
  382 }
  383 
  384 static void
  385 smcbreak(Uart*, int)
  386 {
  387 }
  388 
  389 static void
  390 smckick(Uart *uart)
  391 {
  392         BD *txb;
  393         UartData *ud;
  394         int i;
  395 
  396         if(uart->blocked)
  397                 return;
  398 
  399         ud = uart->regs;
  400         txb = ud->txb;
  401 
  402         if (txb->status & BDReady)
  403                 return; /* Still busy */
  404 
  405         for(i = 0; i < Txsize; i++){
  406                 if(uart->op >= uart->oe && uartstageoutput(uart) == 0)
  407                         break;
  408                 ud->txbuf[i] = *(uart->op++);
  409         }
  410         if (i == 0)
  411                 return;
  412         dcflush(ud->txbuf, Txsize);
  413         txb->length = i;
  414         sync();
  415         txb->status |= BDReady|BDInt;
  416 }
  417 
  418 static void
  419 smcinterrupt(Ureg*, void* u)
  420 {
  421         int i, nc;
  422         char *buf;
  423         BD *rxb;
  424         UartData *ud;
  425         Uart *uart;
  426         uchar events;
  427 
  428         uart = u;
  429         if (uart == nil)
  430                 panic("uart is nil");
  431         ud = uart->regs;
  432         if (ud == nil)
  433                 panic("ud is nil");
  434 
  435         events = ud->smc->smce;
  436         ud->smc->smce = events; /* Clear events */
  437 
  438         if (events & 0x10)
  439                 iprint("smc%d: break\n", ud->smcno);
  440         if (events & 0x4)
  441                 uart->oerr++;
  442         if (events & 0x1){
  443                 /* Receive characters
  444                 */
  445                 rxb = ud->rxb;
  446                 buf = ud->rxbuf;
  447                 dczap(buf, Rxsize);     /* invalidate data cache before copying */
  448                 if ((rxb->status & BDEmpty) == 0){
  449                         nc = rxb->length;
  450                         for (i=0; i<nc; i++)
  451                                 uartrecv(uart, *buf++);
  452                         sync();
  453                         rxb->status |= BDEmpty;
  454                 }else{
  455                         iprint("uartsmc: unexpected receive event\n");
  456                 }
  457         }
  458         if (events & 0x2){
  459                 if ((ud->txb->status & BDReady) == 0)
  460                         uartkick(uart);
  461         }
  462 }
  463 
  464 static void
  465 smcdisable(Uart* uart)
  466 {
  467         SMC *sp;
  468 
  469         sp = ((UartData*)uart->regs)->smc;
  470         sp->smcmr &= ~(Ren | Ten);
  471 }
  472 
  473 static int
  474 getchars(Uart *uart, uchar *cbuf)
  475 {
  476         int i, nc;
  477         char *buf;
  478         BD *rxb;
  479         UartData *ud;
  480 
  481         ud = uart->regs;
  482         rxb = ud->rxb;
  483 
  484         /* Wait for character to show up.
  485         */
  486         buf = ud->rxbuf;
  487         while (rxb->status & BDEmpty)
  488                 ;
  489         nc = rxb->length;
  490         for (i=0; i<nc; i++)
  491                 *cbuf++ = *buf++;
  492         sync();
  493         rxb->status |= BDEmpty;
  494 
  495         return(nc);
  496 }
  497 
  498 static int
  499 smcgetc(Uart *uart)
  500 {
  501         static uchar buf[128], *p;
  502         static int cnt;
  503         char    c;
  504 
  505         if (cnt <= 0) {
  506                 cnt = getchars(uart, buf);
  507                 p = buf;
  508         }
  509         c = *p++;
  510         cnt--;
  511 
  512         return(c);
  513 }
  514 
  515 static void
  516 smcputc(Uart *uart, int c)
  517 {
  518         BD *txb;
  519         UartData *ud;
  520         SMC *smc;
  521 
  522         ud = uart->regs;
  523         txb = ud->txb;
  524         smc = ud->smc;
  525         smc->smcm = 0;
  526 
  527         /* Wait for last character to go.
  528         */
  529         while (txb->status & BDReady)
  530                 ;
  531 
  532         ud->txbuf[0] = c;
  533         dcflush(ud->txbuf, 1);
  534         txb->length = 1;
  535         sync();
  536         txb->status |= BDReady;
  537 
  538         while (txb->status & BDReady)
  539                 ;
  540 }
  541 
  542 PhysUart smcphysuart = {
  543         .name           = "smc",
  544         .pnp                    = smcpnp,
  545         .enable         = smcenable,
  546         .disable                = smcdisable,
  547         .kick                   = smckick,
  548         .dobreak                = smcbreak,
  549         .baud           = smcbaud,
  550         .bits                   = smcbits,
  551         .stop                   = smcstop,
  552         .parity         = smcparity,
  553         .modemctl       = smcmodemctl,
  554         .rts                    = smcrts,
  555         .dtr                    = smcdtr,
  556         .status         = smcstatus,
  557         .fifo                   = smcfifo,
  558         .getc                   = smcgetc,
  559         .putc                   = smcputc,
  560 };
  561 
  562 void
  563 console(void)
  564 {
  565         Uart *uart;
  566         int n;
  567         char *cmd, *p;
  568 
  569         if((p = getconf("console")) == nil)
  570                 return;
  571         n = strtoul(p, &cmd, 0);
  572         if(p == cmd)
  573                 return;
  574         if(n < 0 || n >= nelem(smcuart))
  575                 return;
  576         uart = smcuart + n;
  577 
  578 /*      uartctl(uart, "b115200 l8 pn s1"); */
  579         if(*cmd != '\0')
  580                 uartctl(uart, cmd);
  581         (*uart->phys->enable)(uart, 0);
  582 
  583         consuart = uart;
  584         uart->console = 1;
  585 } 

Cache object: 8e2640bf2f0f8c187ff7ecc88b1957fb


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.