1458db832SDavid du Colombier #include "u.h"
2458db832SDavid du Colombier #include "../port/lib.h"
3458db832SDavid du Colombier #include "mem.h"
4458db832SDavid du Colombier #include "dat.h"
5458db832SDavid du Colombier #include "fns.h"
6458db832SDavid du Colombier #include "io.h"
74de34a7eSDavid du Colombier #include "imm.h"
8458db832SDavid du Colombier #include "../port/error.h"
94de34a7eSDavid du Colombier #include "../ppc/uartsmc.h"
10458db832SDavid du Colombier
11458db832SDavid du Colombier /*
12458db832SDavid du Colombier * PowerPC 8260 SMC UART
13458db832SDavid du Colombier */
14458db832SDavid du Colombier
15458db832SDavid du Colombier enum {
16458db832SDavid du Colombier /* SMC Mode Registers */
17458db832SDavid du Colombier Clen = 0x7800, /* Character length */
18458db832SDavid du Colombier Sl = 0x0400, /* Stop length, 0: one stop bit, 1: two */
19458db832SDavid du Colombier Pen = 0x0200, /* Parity enable */
20458db832SDavid du Colombier Pm = 0x0100, /* Parity mode, 0 is odd */
21458db832SDavid du Colombier Sm = 0x0030, /* SMC mode, two bits */
22458db832SDavid du Colombier SMUart = 0x0020, /* SMC mode, 0b10 is uart */
23458db832SDavid du Colombier Dm = 0x000c, /* Diagnostic mode, 00 is normal */
24458db832SDavid du Colombier Ten = 0x0002, /* Transmit enable, 1 is enabled */
25458db832SDavid du Colombier Ren = 0x0001, /* Receive enable, 1 is enabled */
26458db832SDavid du Colombier
27458db832SDavid du Colombier /* SMC Event/Mask Registers */
28458db832SDavid du Colombier ce_Brke = 0x0040, /* Break end */
29458db832SDavid du Colombier ce_Br = 0x0020, /* Break character received */
30458db832SDavid du Colombier ce_Bsy = 0x0004, /* Busy condition */
31458db832SDavid du Colombier ce_Txb = 0x0002, /* Tx buffer */
32458db832SDavid du Colombier ce_Rxb = 0x0001, /* Rx buffer */
33458db832SDavid du Colombier
34458db832SDavid du Colombier /* Receive/Transmit Buffer Descriptor Control bits */
35458db832SDavid du Colombier BDContin= 1<<9,
36458db832SDavid du Colombier BDIdle= 1<<8,
37458db832SDavid du Colombier BDPreamble= 1<<8,
38458db832SDavid du Colombier BDBreak= 1<<5,
39458db832SDavid du Colombier BDFrame= 1<<4,
40458db832SDavid du Colombier BDParity= 1<<3,
41458db832SDavid du Colombier BDOverrun= 1<<1,
42458db832SDavid du Colombier
43458db832SDavid du Colombier /* Tx and Rx buffer sizes (32 bytes) */
44458db832SDavid du Colombier Rxsize= CACHELINESZ,
45458db832SDavid du Colombier Txsize= CACHELINESZ,
46458db832SDavid du Colombier };
47458db832SDavid du Colombier
48458db832SDavid du Colombier extern PhysUart smcphysuart;
49458db832SDavid du Colombier
50458db832SDavid du Colombier Uart smcuart[Nuart] = {
51458db832SDavid du Colombier {
52458db832SDavid du Colombier .name = "SMC1",
53458db832SDavid du Colombier .baud = 115200,
54458db832SDavid du Colombier .bits = 8,
55458db832SDavid du Colombier .stop = 1,
56458db832SDavid du Colombier .parity = 'n',
57458db832SDavid du Colombier .phys = &smcphysuart,
58458db832SDavid du Colombier .special = 0,
59458db832SDavid du Colombier },
60458db832SDavid du Colombier /* Only configure SMC1 for now
61458db832SDavid du Colombier {
62458db832SDavid du Colombier .name = "SMC2",
63458db832SDavid du Colombier .baud = 115200,
64458db832SDavid du Colombier .bits = 8,
65458db832SDavid du Colombier .stop = 1,
66458db832SDavid du Colombier .parity = 'n',
67458db832SDavid du Colombier .phys = &smcphysuart,
68458db832SDavid du Colombier .special = 0,
69458db832SDavid du Colombier },
70458db832SDavid du Colombier */
71458db832SDavid du Colombier };
72458db832SDavid du Colombier
73458db832SDavid du Colombier int uartinited = 0;
74458db832SDavid du Colombier
75458db832SDavid du Colombier static void smcinterrupt(Ureg*, void*);
76458db832SDavid du Colombier static void smcputc(Uart *uart, int c);
77458db832SDavid du Colombier
784de34a7eSDavid du Colombier int
baudgen(int baud)79458db832SDavid du Colombier baudgen(int baud)
80458db832SDavid du Colombier {
81458db832SDavid du Colombier int d;
82458db832SDavid du Colombier
83458db832SDavid du Colombier d = ((m->brghz+(baud>>1))/baud)>>4;
84458db832SDavid du Colombier if(d >= (1<<12))
85458db832SDavid du Colombier return ((d+15)>>3)|1;
86458db832SDavid du Colombier return d<<1;
87458db832SDavid du Colombier }
88458db832SDavid du Colombier
89458db832SDavid du Colombier static Uart*
smcpnp(void)90458db832SDavid du Colombier smcpnp(void)
91458db832SDavid du Colombier {
92458db832SDavid du Colombier int i;
93458db832SDavid du Colombier
94458db832SDavid du Colombier for (i = 0; i < nelem(smcuart) - 1; i++)
95458db832SDavid du Colombier smcuart[i].next = smcuart + i + 1;
96458db832SDavid du Colombier return smcuart;
97458db832SDavid du Colombier }
98458db832SDavid du Colombier
994de34a7eSDavid du Colombier void
smcsetup(Uart * uart)100*5d9de2d3SDavid du Colombier smcsetup(Uart *uart)
101*5d9de2d3SDavid du Colombier {
102*5d9de2d3SDavid du Colombier Uartsmc *p;
103*5d9de2d3SDavid du Colombier SMC *smc;
104*5d9de2d3SDavid du Colombier UartData *ud;
105*5d9de2d3SDavid du Colombier
106*5d9de2d3SDavid du Colombier ud = uart->regs;
107*5d9de2d3SDavid du Colombier
108*5d9de2d3SDavid du Colombier /* magic addresses */
109*5d9de2d3SDavid du Colombier
110*5d9de2d3SDavid du Colombier p = &m->immr->uartsmc[ud->smcno];
111*5d9de2d3SDavid du Colombier smc = imm->smc + ud->smcno; /* SMC1 */
112*5d9de2d3SDavid du Colombier ud->smc = smc;
113*5d9de2d3SDavid du Colombier ud->usmc = p;
114*5d9de2d3SDavid du Colombier
115*5d9de2d3SDavid du Colombier /* step 0: disable rx/tx */
116*5d9de2d3SDavid du Colombier smc->smcmr &= ~3;
117*5d9de2d3SDavid du Colombier
118*5d9de2d3SDavid du Colombier ioplock();
119*5d9de2d3SDavid du Colombier
120*5d9de2d3SDavid du Colombier /* step 1, Using Port D */
121*5d9de2d3SDavid du Colombier if (ud->smcno != 0)
122*5d9de2d3SDavid du Colombier panic("Don't know how to set Port D bits");
123*5d9de2d3SDavid du Colombier imm->port[SMC1PORT].ppar |= SMRXD1|SMTXD1;
124*5d9de2d3SDavid du Colombier imm->port[SMC1PORT].pdir |= SMTXD1;
125*5d9de2d3SDavid du Colombier imm->port[SMC1PORT].pdir &= ~SMRXD1;
126*5d9de2d3SDavid du Colombier imm->port[SMC1PORT].psor &= ~(SMRXD1|SMTXD1);
127*5d9de2d3SDavid du Colombier
128*5d9de2d3SDavid du Colombier /* step 2: set up brgc1 */
129*5d9de2d3SDavid du Colombier imm->brgc[ud->smcno] = baudgen(uart->baud) | 0x10000;
130*5d9de2d3SDavid du Colombier
131*5d9de2d3SDavid du Colombier /* step 3: route clock to SMC1 */
132*5d9de2d3SDavid du Colombier imm->cmxsmr &= (ud->smcno == 0) ? ~0xb0 : ~0xb; /* clear smcx and smcxcs */
133*5d9de2d3SDavid du Colombier
134*5d9de2d3SDavid du Colombier iopunlock();
135*5d9de2d3SDavid du Colombier
136*5d9de2d3SDavid du Colombier /* step 4: assign a pointer to the SMCparameter RAM */
137*5d9de2d3SDavid du Colombier m->immr->param[ud->smcno].smcbase = (ulong)p - IMMR;
138*5d9de2d3SDavid du Colombier
139*5d9de2d3SDavid du Colombier /* step 6: issue command to CP */
140*5d9de2d3SDavid du Colombier if (ud->smcno == 0)
141*5d9de2d3SDavid du Colombier cpmop(InitRxTx, SMC1ID, 0);
142*5d9de2d3SDavid du Colombier else
143*5d9de2d3SDavid du Colombier cpmop(InitRxTx, SMC2ID, 0);
144*5d9de2d3SDavid du Colombier
145*5d9de2d3SDavid du Colombier /* step 7: protocol parameters */
146*5d9de2d3SDavid du Colombier p->rfcr = 0x30;
147*5d9de2d3SDavid du Colombier p->tfcr = 0x30;
148*5d9de2d3SDavid du Colombier }
149*5d9de2d3SDavid du Colombier
150*5d9de2d3SDavid du Colombier void
smcinit(Uart * uart)151458db832SDavid du Colombier smcinit(Uart *uart)
152458db832SDavid du Colombier {
153458db832SDavid du Colombier Uartsmc *p;
154458db832SDavid du Colombier SMC *smc;
155458db832SDavid du Colombier UartData *ud;
156458db832SDavid du Colombier ulong lcr;
157458db832SDavid du Colombier int bits;
158458db832SDavid du Colombier
159458db832SDavid du Colombier ud = uart->regs;
160458db832SDavid du Colombier
161458db832SDavid du Colombier if (ud->initialized)
162458db832SDavid du Colombier return;
163458db832SDavid du Colombier
1644de34a7eSDavid du Colombier smcsetup(uart); /* Steps 1 through 4, PPC-dependent */
1654de34a7eSDavid du Colombier p = ud->usmc;
1664de34a7eSDavid du Colombier smc = ud->smc;
167458db832SDavid du Colombier
1684de34a7eSDavid du Colombier /* step 5: set up buffer descriptors */
169458db832SDavid du Colombier /* setup my uart structure */
170458db832SDavid du Colombier if (ud->rxb == nil)
171458db832SDavid du Colombier ud->rxb = bdalloc(1);
172458db832SDavid du Colombier if (ud->txb == nil)
173458db832SDavid du Colombier ud->txb = bdalloc(1);
174458db832SDavid du Colombier
1754de34a7eSDavid du Colombier p->rbase = ((ulong)ud->rxb) - (ulong)IMMR;
1764de34a7eSDavid du Colombier p->tbase = ((ulong)ud->txb) - (ulong)IMMR;
177458db832SDavid du Colombier
178458db832SDavid du Colombier /* step 8: receive buffer size */
179458db832SDavid du Colombier p->mrblr = Rxsize;
180458db832SDavid du Colombier
181458db832SDavid du Colombier /* step 9: */
182458db832SDavid du Colombier p->maxidl = 15;
183458db832SDavid du Colombier
184458db832SDavid du Colombier /* step 10: */
185458db832SDavid du Colombier p->brkln = 0;
186458db832SDavid du Colombier p->brkec = 0;
187458db832SDavid du Colombier
188458db832SDavid du Colombier /* step 11: */
189458db832SDavid du Colombier p->brkcr = 0;
190458db832SDavid du Colombier
191458db832SDavid du Colombier /* step 12: setup receive buffer */
192458db832SDavid du Colombier ud->rxb->status = BDEmpty|BDWrap|BDInt;
193458db832SDavid du Colombier ud->rxb->length = 0;
194458db832SDavid du Colombier ud->rxbuf = xspanalloc(Rxsize, 0, CACHELINESZ);
195458db832SDavid du Colombier ud->rxb->addr = PADDR(ud->rxbuf);
196458db832SDavid du Colombier
197458db832SDavid du Colombier /* step 13: step transmit buffer */
198458db832SDavid du Colombier ud->txb->status = BDWrap|BDInt;
199458db832SDavid du Colombier ud->txb->length = 0;
200458db832SDavid du Colombier ud->txbuf = xspanalloc(Txsize, 0, CACHELINESZ);
201458db832SDavid du Colombier ud->txb->addr = PADDR(ud->txbuf);
202458db832SDavid du Colombier
203458db832SDavid du Colombier /* step 14: clear events */
204458db832SDavid du Colombier smc->smce = ce_Brke | ce_Br | ce_Bsy | ce_Txb | ce_Rxb;
205458db832SDavid du Colombier
206458db832SDavid du Colombier /*
207458db832SDavid du Colombier * step 15: enable interrupts (done later)
208458db832SDavid du Colombier * smc->smcm = ce_Brke | ce_Br | ce_Bsy | ce_Txb | ce_Rxb;
209458db832SDavid du Colombier */
210458db832SDavid du Colombier
211458db832SDavid du Colombier /* step 17: set parity, no of bits, UART mode, ... */
212458db832SDavid du Colombier lcr = SMUart;
213458db832SDavid du Colombier bits = uart->bits + 1;
214458db832SDavid du Colombier
215458db832SDavid du Colombier switch(uart->parity){
216458db832SDavid du Colombier case 'e':
217458db832SDavid du Colombier lcr |= (Pen|Pm);
218458db832SDavid du Colombier bits +=1;
219458db832SDavid du Colombier break;
220458db832SDavid du Colombier case 'o':
221458db832SDavid du Colombier lcr |= Pen;
222458db832SDavid du Colombier bits +=1;
223458db832SDavid du Colombier break;
224458db832SDavid du Colombier case 'n':
225458db832SDavid du Colombier default:
226458db832SDavid du Colombier break;
227458db832SDavid du Colombier }
228458db832SDavid du Colombier
229458db832SDavid du Colombier if(uart->stop == 2){
230458db832SDavid du Colombier lcr |= Sl;
231458db832SDavid du Colombier bits += 1;
232458db832SDavid du Colombier }
233458db832SDavid du Colombier
234458db832SDavid du Colombier /* Set new value and reenable if device was previously enabled */
235458db832SDavid du Colombier smc->smcmr = lcr | bits <<11 | 0x3;
236458db832SDavid du Colombier
237458db832SDavid du Colombier ud->initialized = 1;
238458db832SDavid du Colombier }
239458db832SDavid du Colombier
240458db832SDavid du Colombier static void
smcenable(Uart * uart,int intenb)241458db832SDavid du Colombier smcenable(Uart *uart, int intenb)
242458db832SDavid du Colombier {
243458db832SDavid du Colombier UartData *ud;
244458db832SDavid du Colombier SMC *smc;
245458db832SDavid du Colombier int nr;
246458db832SDavid du Colombier
247458db832SDavid du Colombier nr = uart - smcuart;
248458db832SDavid du Colombier if (nr < 0 || nr > Nuart)
249458db832SDavid du Colombier panic("No SMC %d", nr);
250458db832SDavid du Colombier ud = uartdata + nr;
251458db832SDavid du Colombier ud->smcno = nr;
252458db832SDavid du Colombier uart->regs = ud;
253458db832SDavid du Colombier if (ud->initialized == 0)
254458db832SDavid du Colombier smcinit(uart);
255458db832SDavid du Colombier if (ud->enabled || intenb == 0)
256458db832SDavid du Colombier return;
257458db832SDavid du Colombier smc = ud->smc;
258458db832SDavid du Colombier /* clear events */
259458db832SDavid du Colombier smc->smce = ce_Brke | ce_Br | ce_Bsy | ce_Txb | ce_Rxb;
260458db832SDavid du Colombier /* enable interrupts */
261458db832SDavid du Colombier smc->smcm = ce_Brke | ce_Br | ce_Bsy | ce_Txb | ce_Rxb;
2624de34a7eSDavid du Colombier intrenable(VecSMC1 + ud->smcno, smcinterrupt, uart, uart->name);
263458db832SDavid du Colombier ud->enabled = 1;
264458db832SDavid du Colombier }
265458db832SDavid du Colombier
266458db832SDavid du Colombier static long
smcstatus(Uart * uart,void * buf,long n,long offset)267458db832SDavid du Colombier smcstatus(Uart* uart, void* buf, long n, long offset)
268458db832SDavid du Colombier {
269458db832SDavid du Colombier SMC *sp;
270458db832SDavid du Colombier char p[128];
271458db832SDavid du Colombier
272458db832SDavid du Colombier sp = ((UartData*)uart->regs)->smc;
273458db832SDavid du Colombier snprint(p, sizeof p, "b%d c%d e%d l%d m0 p%c s%d i1\n"
274458db832SDavid du Colombier "dev(%d) type(%d) framing(%d) overruns(%d)\n",
275458db832SDavid du Colombier
276458db832SDavid du Colombier uart->baud,
277458db832SDavid du Colombier uart->hup_dcd,
278458db832SDavid du Colombier uart->hup_dsr,
279458db832SDavid du Colombier ((sp->smcmr & Clen) >>11) - ((sp->smcmr&Pen) ? 1 : 0) - ((sp->smcmr&Sl) ? 2 : 1),
280458db832SDavid du Colombier (sp->smcmr & Pen) ? ((sp->smcmr & Pm) ? 'e': 'o'): 'n',
281458db832SDavid du Colombier (sp->smcmr & Sl) ? 2: 1,
282458db832SDavid du Colombier
283458db832SDavid du Colombier uart->dev,
284458db832SDavid du Colombier uart->type,
285458db832SDavid du Colombier uart->ferr,
286458db832SDavid du Colombier uart->oerr
287458db832SDavid du Colombier );
288458db832SDavid du Colombier n = readstr(offset, buf, n, p);
289458db832SDavid du Colombier free(p);
290458db832SDavid du Colombier
291458db832SDavid du Colombier return n;
292458db832SDavid du Colombier }
293458db832SDavid du Colombier
294458db832SDavid du Colombier static void
smcfifo(Uart *,int)295458db832SDavid du Colombier smcfifo(Uart*, int)
296458db832SDavid du Colombier {
297458db832SDavid du Colombier /*
298458db832SDavid du Colombier * Toggle FIFOs:
299458db832SDavid du Colombier * if none, do nothing;
300458db832SDavid du Colombier * reset the Rx and Tx FIFOs;
301458db832SDavid du Colombier * empty the Rx buffer and clear any interrupt conditions;
302458db832SDavid du Colombier * if enabling, try to turn them on.
303458db832SDavid du Colombier */
304458db832SDavid du Colombier return;
305458db832SDavid du Colombier }
306458db832SDavid du Colombier
307458db832SDavid du Colombier static void
smcdtr(Uart *,int)308458db832SDavid du Colombier smcdtr(Uart*, int)
309458db832SDavid du Colombier {
310458db832SDavid du Colombier }
311458db832SDavid du Colombier
312458db832SDavid du Colombier static void
smcrts(Uart *,int)313458db832SDavid du Colombier smcrts(Uart*, int)
314458db832SDavid du Colombier {
315458db832SDavid du Colombier }
316458db832SDavid du Colombier
317458db832SDavid du Colombier static void
smcmodemctl(Uart *,int)318458db832SDavid du Colombier smcmodemctl(Uart*, int)
319458db832SDavid du Colombier {
320458db832SDavid du Colombier }
321458db832SDavid du Colombier
322458db832SDavid du Colombier static int
smcparity(Uart * uart,int parity)323458db832SDavid du Colombier smcparity(Uart* uart, int parity)
324458db832SDavid du Colombier {
325458db832SDavid du Colombier int lcr;
326458db832SDavid du Colombier SMC *sp;
327458db832SDavid du Colombier
328458db832SDavid du Colombier sp = ((UartData*)uart->regs)->smc;
329458db832SDavid du Colombier
330458db832SDavid du Colombier lcr = sp->smcmr & ~(Pen|Pm);
331458db832SDavid du Colombier
332458db832SDavid du Colombier /* Disable transmitter/receiver. */
333458db832SDavid du Colombier sp->smcmr &= ~(Ren | Ten);
334458db832SDavid du Colombier
335458db832SDavid du Colombier switch(parity){
336458db832SDavid du Colombier case 'e':
337458db832SDavid du Colombier lcr |= (Pen|Pm);
338458db832SDavid du Colombier break;
339458db832SDavid du Colombier case 'o':
340458db832SDavid du Colombier lcr |= Pen;
341458db832SDavid du Colombier break;
342458db832SDavid du Colombier case 'n':
343458db832SDavid du Colombier default:
344458db832SDavid du Colombier break;
345458db832SDavid du Colombier }
346458db832SDavid du Colombier /* Set new value and reenable if device was previously enabled */
347458db832SDavid du Colombier sp->smcmr = lcr;
348458db832SDavid du Colombier
349458db832SDavid du Colombier uart->parity = parity;
350458db832SDavid du Colombier
351458db832SDavid du Colombier return 0;
352458db832SDavid du Colombier }
353458db832SDavid du Colombier
354458db832SDavid du Colombier static int
smcstop(Uart * uart,int stop)355458db832SDavid du Colombier smcstop(Uart* uart, int stop)
356458db832SDavid du Colombier {
357458db832SDavid du Colombier int lcr, bits;
358458db832SDavid du Colombier SMC *sp;
359458db832SDavid du Colombier
360458db832SDavid du Colombier sp = ((UartData*)uart->regs)->smc;
361458db832SDavid du Colombier lcr = sp->smcmr & ~(Sl | Clen);
362458db832SDavid du Colombier
363458db832SDavid du Colombier /* Disable transmitter/receiver. */
364458db832SDavid du Colombier sp->smcmr &= ~(Ren | Ten);
365458db832SDavid du Colombier
366458db832SDavid du Colombier switch(stop){
367458db832SDavid du Colombier case 1:
368458db832SDavid du Colombier break;
369458db832SDavid du Colombier case 2:
370458db832SDavid du Colombier lcr |= Sl;
371458db832SDavid du Colombier break;
372458db832SDavid du Colombier default:
373458db832SDavid du Colombier return -1;
374458db832SDavid du Colombier }
375458db832SDavid du Colombier
376458db832SDavid du Colombier bits = uart->bits + ((lcr & Pen) ? 1 : 0) + ((lcr & Sl) ? 2 : 1);
377458db832SDavid du Colombier lcr |= bits<<11;
378458db832SDavid du Colombier
379458db832SDavid du Colombier /* Set new value and reenable if device was previously enabled */
380458db832SDavid du Colombier sp->smcmr = lcr;
381458db832SDavid du Colombier
382458db832SDavid du Colombier uart->stop = stop;
383458db832SDavid du Colombier
384458db832SDavid du Colombier return 0;
385458db832SDavid du Colombier }
386458db832SDavid du Colombier
387458db832SDavid du Colombier static int
smcbits(Uart * uart,int bits)388458db832SDavid du Colombier smcbits(Uart* uart, int bits)
389458db832SDavid du Colombier {
390458db832SDavid du Colombier int lcr, b;
391458db832SDavid du Colombier SMC *sp;
392458db832SDavid du Colombier
393458db832SDavid du Colombier if (bits < 5 || bits > 14)
394458db832SDavid du Colombier return -1;
395458db832SDavid du Colombier
396458db832SDavid du Colombier sp = ((UartData*)uart->regs)->smc;
397458db832SDavid du Colombier lcr = sp->smcmr & ~Clen;
398458db832SDavid du Colombier
399458db832SDavid du Colombier b = bits + ((sp->smcmr & Pen) ? 1 : 0) + ((sp->smcmr & Sl) ? 2 : 1);
400458db832SDavid du Colombier
401458db832SDavid du Colombier if (b > 15)
402458db832SDavid du Colombier return -1;
403458db832SDavid du Colombier
404458db832SDavid du Colombier /* Disable transmitter/receiver */
405458db832SDavid du Colombier sp->smcmr &= ~(Ren | Ten);
406458db832SDavid du Colombier
407458db832SDavid du Colombier /* Set new value and reenable if device was previously enabled */
408458db832SDavid du Colombier sp->smcmr = lcr | b<<11;
409458db832SDavid du Colombier
410458db832SDavid du Colombier uart->bits = bits;
411458db832SDavid du Colombier
412458db832SDavid du Colombier return 0;
413458db832SDavid du Colombier }
414458db832SDavid du Colombier
415458db832SDavid du Colombier static int
smcbaud(Uart * uart,int baud)416458db832SDavid du Colombier smcbaud(Uart* uart, int baud)
417458db832SDavid du Colombier {
418458db832SDavid du Colombier int i;
419458db832SDavid du Colombier SMC *sp;
420458db832SDavid du Colombier
421458db832SDavid du Colombier if (uart->enabled){
422458db832SDavid du Colombier sp = ((UartData*)uart->regs)->smc;
423458db832SDavid du Colombier
424458db832SDavid du Colombier if(uart->freq == 0 || baud <= 0)
425458db832SDavid du Colombier return -1;
426458db832SDavid du Colombier
4274de34a7eSDavid du Colombier i = sp - imm->smc;
4284de34a7eSDavid du Colombier imm->brgc[i] = (((m->brghz >> 4) / baud) << 1) | 0x00010000;
429458db832SDavid du Colombier }
430458db832SDavid du Colombier uart->baud = baud;
431458db832SDavid du Colombier
432458db832SDavid du Colombier return 0;
433458db832SDavid du Colombier }
434458db832SDavid du Colombier
435458db832SDavid du Colombier static void
smcbreak(Uart *,int)436458db832SDavid du Colombier smcbreak(Uart*, int)
437458db832SDavid du Colombier {
438458db832SDavid du Colombier }
439458db832SDavid du Colombier
440458db832SDavid du Colombier static void
smckick(Uart * uart)441458db832SDavid du Colombier smckick(Uart *uart)
442458db832SDavid du Colombier {
443458db832SDavid du Colombier BD *txb;
444458db832SDavid du Colombier UartData *ud;
445458db832SDavid du Colombier int i;
446458db832SDavid du Colombier
447458db832SDavid du Colombier if(uart->blocked)
448458db832SDavid du Colombier return;
449458db832SDavid du Colombier
450458db832SDavid du Colombier ud = uart->regs;
451458db832SDavid du Colombier txb = ud->txb;
452458db832SDavid du Colombier
453458db832SDavid du Colombier if (txb->status & BDReady)
454458db832SDavid du Colombier return; /* Still busy */
455458db832SDavid du Colombier
456458db832SDavid du Colombier for(i = 0; i < Txsize; i++){
457458db832SDavid du Colombier if(uart->op >= uart->oe && uartstageoutput(uart) == 0)
458458db832SDavid du Colombier break;
459458db832SDavid du Colombier ud->txbuf[i] = *(uart->op++);
460458db832SDavid du Colombier }
461458db832SDavid du Colombier if (i == 0)
462458db832SDavid du Colombier return;
463458db832SDavid du Colombier dcflush(ud->txbuf, Txsize);
464458db832SDavid du Colombier txb->length = i;
465458db832SDavid du Colombier sync();
466458db832SDavid du Colombier txb->status |= BDReady|BDInt;
467458db832SDavid du Colombier }
468458db832SDavid du Colombier
469458db832SDavid du Colombier static void
smcinterrupt(Ureg *,void * u)470458db832SDavid du Colombier smcinterrupt(Ureg*, void* u)
471458db832SDavid du Colombier {
472458db832SDavid du Colombier int i, nc;
473458db832SDavid du Colombier char *buf;
474458db832SDavid du Colombier BD *rxb;
475458db832SDavid du Colombier UartData *ud;
476458db832SDavid du Colombier Uart *uart;
477458db832SDavid du Colombier uchar events;
478458db832SDavid du Colombier
479458db832SDavid du Colombier uart = u;
480458db832SDavid du Colombier if (uart == nil)
481458db832SDavid du Colombier panic("uart is nil");
482458db832SDavid du Colombier ud = uart->regs;
483458db832SDavid du Colombier if (ud == nil)
484458db832SDavid du Colombier panic("ud is nil");
485458db832SDavid du Colombier
486458db832SDavid du Colombier events = ud->smc->smce;
487458db832SDavid du Colombier ud->smc->smce = events; /* Clear events */
488458db832SDavid du Colombier
489458db832SDavid du Colombier if (events & 0x10)
490458db832SDavid du Colombier iprint("smc%d: break\n", ud->smcno);
491458db832SDavid du Colombier if (events & 0x4)
492458db832SDavid du Colombier uart->oerr++;
493458db832SDavid du Colombier if (events & 0x1){
494458db832SDavid du Colombier /* Receive characters
495458db832SDavid du Colombier */
496458db832SDavid du Colombier rxb = ud->rxb;
497458db832SDavid du Colombier buf = ud->rxbuf;
498458db832SDavid du Colombier dczap(buf, Rxsize); /* invalidate data cache before copying */
499458db832SDavid du Colombier if ((rxb->status & BDEmpty) == 0){
500458db832SDavid du Colombier nc = rxb->length;
501458db832SDavid du Colombier for (i=0; i<nc; i++)
502458db832SDavid du Colombier uartrecv(uart, *buf++);
503458db832SDavid du Colombier sync();
504458db832SDavid du Colombier rxb->status |= BDEmpty;
505458db832SDavid du Colombier }else{
506458db832SDavid du Colombier iprint("uartsmc: unexpected receive event\n");
507458db832SDavid du Colombier }
508458db832SDavid du Colombier }
509458db832SDavid du Colombier if (events & 0x2){
510458db832SDavid du Colombier if ((ud->txb->status & BDReady) == 0)
511458db832SDavid du Colombier uartkick(uart);
512458db832SDavid du Colombier }
513458db832SDavid du Colombier }
514458db832SDavid du Colombier
515458db832SDavid du Colombier static void
smcdisable(Uart * uart)516458db832SDavid du Colombier smcdisable(Uart* uart)
517458db832SDavid du Colombier {
518458db832SDavid du Colombier SMC *sp;
519458db832SDavid du Colombier
520458db832SDavid du Colombier sp = ((UartData*)uart->regs)->smc;
521458db832SDavid du Colombier sp->smcmr &= ~(Ren | Ten);
522458db832SDavid du Colombier }
523458db832SDavid du Colombier
524458db832SDavid du Colombier static int
getchars(Uart * uart,uchar * cbuf)525458db832SDavid du Colombier getchars(Uart *uart, uchar *cbuf)
526458db832SDavid du Colombier {
527458db832SDavid du Colombier int i, nc;
528458db832SDavid du Colombier char *buf;
529458db832SDavid du Colombier BD *rxb;
530458db832SDavid du Colombier UartData *ud;
531458db832SDavid du Colombier
532458db832SDavid du Colombier ud = uart->regs;
533458db832SDavid du Colombier rxb = ud->rxb;
534458db832SDavid du Colombier
535458db832SDavid du Colombier /* Wait for character to show up.
536458db832SDavid du Colombier */
537458db832SDavid du Colombier buf = ud->rxbuf;
538458db832SDavid du Colombier while (rxb->status & BDEmpty)
539458db832SDavid du Colombier ;
540458db832SDavid du Colombier nc = rxb->length;
541458db832SDavid du Colombier for (i=0; i<nc; i++)
542458db832SDavid du Colombier *cbuf++ = *buf++;
543458db832SDavid du Colombier sync();
544458db832SDavid du Colombier rxb->status |= BDEmpty;
545458db832SDavid du Colombier
546458db832SDavid du Colombier return(nc);
547458db832SDavid du Colombier }
548458db832SDavid du Colombier
549458db832SDavid du Colombier static int
smcgetc(Uart * uart)550458db832SDavid du Colombier smcgetc(Uart *uart)
551458db832SDavid du Colombier {
552458db832SDavid du Colombier static uchar buf[128], *p;
553458db832SDavid du Colombier static int cnt;
554458db832SDavid du Colombier char c;
555458db832SDavid du Colombier
556458db832SDavid du Colombier if (cnt <= 0) {
557458db832SDavid du Colombier cnt = getchars(uart, buf);
558458db832SDavid du Colombier p = buf;
559458db832SDavid du Colombier }
560458db832SDavid du Colombier c = *p++;
561458db832SDavid du Colombier cnt--;
562458db832SDavid du Colombier
563458db832SDavid du Colombier return(c);
564458db832SDavid du Colombier }
565458db832SDavid du Colombier
566458db832SDavid du Colombier static void
smcputc(Uart * uart,int c)567458db832SDavid du Colombier smcputc(Uart *uart, int c)
568458db832SDavid du Colombier {
569458db832SDavid du Colombier BD *txb;
570458db832SDavid du Colombier UartData *ud;
571458db832SDavid du Colombier SMC *smc;
572458db832SDavid du Colombier
573458db832SDavid du Colombier ud = uart->regs;
574458db832SDavid du Colombier txb = ud->txb;
575458db832SDavid du Colombier smc = ud->smc;
576458db832SDavid du Colombier smc->smcm = 0;
577458db832SDavid du Colombier
578458db832SDavid du Colombier /* Wait for last character to go.
579458db832SDavid du Colombier */
580458db832SDavid du Colombier while (txb->status & BDReady)
581458db832SDavid du Colombier ;
582458db832SDavid du Colombier
583458db832SDavid du Colombier ud->txbuf[0] = c;
584458db832SDavid du Colombier dcflush(ud->txbuf, 1);
585458db832SDavid du Colombier txb->length = 1;
586458db832SDavid du Colombier sync();
587458db832SDavid du Colombier txb->status |= BDReady;
588458db832SDavid du Colombier
589458db832SDavid du Colombier while (txb->status & BDReady)
590458db832SDavid du Colombier ;
591458db832SDavid du Colombier }
592458db832SDavid du Colombier
593458db832SDavid du Colombier PhysUart smcphysuart = {
594458db832SDavid du Colombier .name = "smc",
595458db832SDavid du Colombier .pnp = smcpnp,
596458db832SDavid du Colombier .enable = smcenable,
597458db832SDavid du Colombier .disable = smcdisable,
598458db832SDavid du Colombier .kick = smckick,
599458db832SDavid du Colombier .dobreak = smcbreak,
600458db832SDavid du Colombier .baud = smcbaud,
601458db832SDavid du Colombier .bits = smcbits,
602458db832SDavid du Colombier .stop = smcstop,
603458db832SDavid du Colombier .parity = smcparity,
604458db832SDavid du Colombier .modemctl = smcmodemctl,
605458db832SDavid du Colombier .rts = smcrts,
606458db832SDavid du Colombier .dtr = smcdtr,
607458db832SDavid du Colombier .status = smcstatus,
608458db832SDavid du Colombier .fifo = smcfifo,
609458db832SDavid du Colombier .getc = smcgetc,
610458db832SDavid du Colombier .putc = smcputc,
611458db832SDavid du Colombier };
612458db832SDavid du Colombier
613458db832SDavid du Colombier void
console(void)614458db832SDavid du Colombier console(void)
615458db832SDavid du Colombier {
616458db832SDavid du Colombier Uart *uart;
617458db832SDavid du Colombier int n;
618458db832SDavid du Colombier char *cmd, *p;
619458db832SDavid du Colombier
620458db832SDavid du Colombier if((p = getconf("console")) == nil)
621458db832SDavid du Colombier return;
622458db832SDavid du Colombier n = strtoul(p, &cmd, 0);
623458db832SDavid du Colombier if(p == cmd)
624458db832SDavid du Colombier return;
625458db832SDavid du Colombier if(n < 0 || n >= nelem(smcuart))
626458db832SDavid du Colombier return;
627458db832SDavid du Colombier uart = smcuart + n;
628458db832SDavid du Colombier
629458db832SDavid du Colombier /* uartctl(uart, "b115200 l8 pn s1"); */
630458db832SDavid du Colombier if(*cmd != '\0')
631458db832SDavid du Colombier uartctl(uart, cmd);
632458db832SDavid du Colombier (*uart->phys->enable)(uart, 0);
633458db832SDavid du Colombier
634458db832SDavid du Colombier consuart = uart;
635458db832SDavid du Colombier uart->console = 1;
636458db832SDavid du Colombier }
637