9os

Experimental kernel using plan9 ideas for embedded device
git clone git://git.simple-cc.org/9os
Log | Files | Refs | README | LICENSE

pl011.c (7455B)


      1 #include <os9/os9.h>
      2 
      3 #include "dev.h"
      4 #include "uart.h"
      5 
      6 enum phyregs {
      7 	UARTDR,      /* Data register */
      8 	UARTRSR,     /* Receive status register */
      9 	RES1,        /* Reserved */
     10 	RES2,        /* Reserved */
     11 	RES3,        /* Reserved */
     12 	RES4,        /* Reserved */
     13 	UARTFR,      /* Flag register */
     14 	RES5,        /* Reserved */
     15 	UARTILPR,    /* IrDA low-power count register */
     16 	UARTIBRD,    /* Integer baud rate */
     17 	UARTFBRD,    /* Fractional baud rate register */
     18 	UARTLCR_H,   /* Line control register */
     19 	UARTCR,      /* Control register */
     20 	UARTIFLS,    /* Interrupt FIFO level select register */
     21 	UARTIMSC,    /* Interrupt mask set/clear register */
     22 	UARTRIS,     /* Raw interrupt status register */
     23 	UARTMIS,     /* Masked interrupt register */
     24 	UARTICR,     /* Interrupt clear register */
     25 	UARTDMACR,   /* DMA control register */
     26 	RES6,        /* Reserved */
     27 	RES7,        /* Reserved */
     28 	RES8,        /* Reserved */
     29 	RES9,        /* Reserved */
     30 	UARTPID0,    /* UART Periph ID0 */
     31 	UARTPID1,    /* UART Periph ID1 */
     32 	UARTPID2,    /* UART Periph ID2 */
     33 	UARTPID3,    /* UART Periph ID3 */
     34 	UARTCID0,    /* UART Cell ID0 */
     35 	UARTCID1,    /* UART Cell ID1 */
     36 	UARTCID2,    /* UART Cell ID2 */
     37 	UARTCID3,    /* UART Cell ID3 */
     38 };
     39 
     40 enum eoi {
     41 	RIMC   = 1 << 0,    /* clears UARTRIINTR */
     42 	CTSMIC = 1 << 1,    /* clears UARTCTSINTR */
     43 	DCDMIC = 1 << 2,    /* clears UARTDCDINTR */
     44 	DSRMIC = 1 << 3,    /* clears UARTDSRINTR */
     45 	RXIC   = 1 << 4,    /* clears UARTRXINTR */
     46 	TXIC   = 1 << 5,    /* clears UARTTXINTR */
     47 	RTIC   = 1 << 6,    /* clears UARTRTINTR */
     48 	FEIC   = 1 << 7,    /* clears UARTFEINTR */
     49 	PEIC   = 1 << 8,    /* clears UARTPEINTR */
     50 	BEIC   = 1 << 9,    /* clears UARTBEINTR */
     51 	OEIC   = 1 << 10,   /* clears UARTOEINTR */
     52 };
     53 
     54 #define ALLIC (RIMC|CTSMIC|DCDMIC|DSRMIC|RXIC|TXIC|\
     55                RTIC|FEIC|PEIC|BEIC|OEIC)
     56 
     57 enum uartlcr_h {
     58 	BRK    = 1 << 0,    /* send break */
     59 	PEN    = 1 << 1,    /* Parity enable */
     60 	EPS    = 1 << 2,    /* Even parity enable */
     61 	STP2   = 1 << 3,    /* Two stop bits */
     62 	FEN    = 1 << 4,    /* Enable FIFOs */
     63 	WLEN_5 = 0 << 5,    /* word lenght (5 bits) */
     64 	WLEN_6 = 1 << 5,    /* word lenght (6 bits) */
     65 	WLEN_7 = 2 << 5,    /* word lenght (7 bits) */
     66 	WLEN_8 = 3 << 5,    /* word lenght (8 bits) */
     67 	WLEN   = 3 << 5,    /* clean mask for word length */
     68 	SPS    = 1 << 7,    /* Stick parity select */
     69 };
     70 
     71 enum uartcr {
     72 	UARTEN = 1 << 0,    /* UART enable */
     73 	SIREN  = 1 << 1,    /* SIR enable */
     74 	SIRLP  = 1 << 2,    /* SIR low power IrDA mode */
     75 	LBE    = 1 << 7,    /* Loopback enable */
     76 	TXE    = 1 << 8,    /* TX enable */
     77 	RXE    = 1 << 9,    /* RX enable */
     78 	DTR    = 1 << 10,   /* Data transmit ready */
     79 	RTS    = 1 << 11,   /* Request to send */
     80 	OUT1   = 1 << 12,   /* can be used for DCD */
     81 	OUT2   = 1 << 13,   /* can be used for RI */
     82 	RSTEN  = 1 << 14,   /* RTS hardware flow control mode */
     83 	CTSEN  = 1 << 15,   /* CTS hardware flow control mode */
     84 };
     85 
     86 #define ALLCR (UARTEN|SIREN|SIRLP|LBE|TXE|RXE|DTR|\
     87                RTS|OUT1|OUT2|RSTEN|CTSEN)
     88 
     89 enum uartfr {
     90 	FR_CTS  = 1 << 0,     /* CTS flag */
     91 	FR_DSR  = 1 << 1,     /* DSR flag */
     92 	FR_DCD  = 1 << 2,     /* DCD flag */
     93 	FR_BUSY = 1 << 3,     /* UART busy transmiting */
     94 	FR_RXFE = 1 << 4,     /* Receive FIFO empty */
     95 	FR_TXFF = 1 << 5,     /* Transmit FIFO full */
     96 	FR_RXFF = 1 << 6,     /* Receive FIFO full */
     97 	FR_TXFE = 1 << 7,     /* Transmit FIFO empty */
     98 	FR_RI   = 1 << 8,     /* Ring indicator */
     99 };
    100 
    101 enum uartifls {
    102 	TXIFLSEL = 0,
    103 	RXIFLSEL = 3,
    104 };
    105 
    106 static unsigned long
    107 plin(Uart *up, int reg)
    108 {
    109 	char *addr = up->base;
    110 
    111 	addr += reg * 4;
    112 	return inm32(addr);
    113 }
    114 
    115 static void
    116 plout(Uart *up, int reg, unsigned long val)
    117 {
    118 	char *addr = up->base;
    119 
    120 	addr += reg * 4;
    121 	outm32(val, addr);
    122 }
    123 
    124 static int
    125 setbauds(Uart *up, long rate)
    126 {
    127 	unsigned div;
    128 	unsigned long cr;
    129 
    130 	div = (up->clk * 4) / rate;
    131 	if (div == 0)
    132 		return -1;
    133 
    134 	cr = plin(up, UARTCR);
    135 	plout(up, UARTCR, cr & ~UARTEN);
    136 	plout(up, UARTIBRD, div >> 6);
    137 	plout(up, UARTFBRD, div & 0x3f);
    138 	up->rate = rate;
    139 	plout(up, UARTCR, cr | UARTEN);
    140 
    141 	return 0;
    142 }
    143 
    144 static void
    145 pl011init(Uart *up, Attr *attr)
    146 {
    147 	unsigned long cr;
    148 
    149 	cr = plin(up, UARTCR) & ~ALLCR;
    150 	plout(up, UARTCR, cr);
    151 	plout(up, UARTICR, ALLIC);
    152 	plout(up, UARTRSR, 0);
    153 	plout(up, UARTLCR_H, WLEN_8);
    154 	plout(up, UARTIMSC, 0);
    155 	plout(up, UARTIBRD, 0);
    156 	plout(up, UARTFBRD, 0);
    157 	plout(up, UARTCR, cr | UARTEN | TXE | RXE);
    158 
    159 	up->rate = 0;
    160 	up->nbits = 8;
    161 	up->nstop = 1;
    162 	up->hang = 0;
    163 	up->ctsflow = 0;
    164 	up->parity = NPARITY;
    165 	up->fifo = 0;
    166 }
    167 
    168 static int
    169 pl011read(Uart *up, void *buf, int n)
    170 {
    171 	int i;
    172 	char *bp = buf;
    173 
    174 	for (i = 0; i < n; i++) {
    175 		while ((plin(up, UARTFR) & FR_RXFE) != 0)
    176 			;
    177 		bp[i] = plin(up, UARTDR);
    178 	}
    179 	return n;
    180 }
    181 
    182 static int
    183 pl011write(Uart *up, void *buf, int n)
    184 {
    185 	int i;
    186 	char *bp = buf;
    187 
    188 	for (i = 0; i < n; i++) {
    189 		while ((plin(up, UARTFR) & FR_TXFF) != 0)
    190 			;
    191 		plout(up, UARTDR, bp[i]);
    192 	}
    193 	return n;
    194 }
    195 
    196 static int
    197 pl011signal(Uart *up, int sign, int val)
    198 {
    199 	unsigned cr;
    200 
    201 	cr = plin(up, UARTCR);
    202 
    203 	switch (sign) {
    204 	case SIG_DTR:
    205 		cr &= ~RTS;
    206 		if (val)
    207 			cr |= RTS;
    208 		up->dtr = (val != 0);
    209 		break;
    210 	case SIG_RTS:
    211 		cr &= ~RTS;
    212 		if (val)
    213 			cr |= RTS;
    214 		up->rts = (val != 0);
    215 		break;
    216 	default:
    217 		return -1;
    218 	}
    219 
    220 	plout(up, UARTCR, cr);
    221 
    222 	return 1;
    223 }
    224 
    225 static int
    226 pl011flush(Uart *up)
    227 {
    228 	unsigned crl;
    229 
    230 	crl = plin(up, UARTLCR_H);
    231 
    232 	plout(up, UARTLCR_H, crl & ~FEN);
    233 	plout(up, UARTLCR_H, crl);
    234 
    235 	return 0;
    236 }
    237 
    238 static int
    239 pl011fifo(Uart *up, int trigger)
    240 {
    241 	unsigned fil, cr, val;
    242 
    243         cr = plin(up, UARTCR);
    244 
    245 	up->fifo = trigger;
    246 	switch (trigger) {
    247 	case 0:
    248 	case 1:
    249 		plout(up, UARTCR, cr & ~FEN);
    250 		return 0;
    251 	case 4:
    252 		val = 1;
    253 	case 8:
    254 		val = 2;
    255 		break;
    256 	default:
    257 		val = 4;
    258 		break;
    259 	}
    260 	fil = (val << TXIFLSEL) | (val << RXIFLSEL);
    261 
    262 	plout(up, UARTCR, cr | FEN);
    263 	plout(up, UARTIFLS, fil);
    264 
    265 	return 0;
    266 }
    267 
    268 static int
    269 pl011bits(Uart *up, int nbits)
    270 {
    271 	unsigned lcr_h, val;
    272 
    273 	lcr_h = plin(up, UARTLCR_H);
    274 
    275 	switch (nbits) {
    276 	case 5:
    277 		val = WLEN_5;
    278 		break;
    279 	case 6:
    280 		val = WLEN_6;
    281 		break;
    282 	case 7:
    283 		val = WLEN_7;
    284 		break;
    285 	case 8:
    286 		val = WLEN_8;
    287 		break;
    288 	default:
    289 		return -1;
    290 	}
    291 
    292 	up->nbits = val;
    293 	lcr_h &= ~WLEN;
    294 	lcr_h |= val;
    295 	plout(up, UARTLCR_H, lcr_h);
    296 
    297 	return 0;
    298 }
    299 
    300 static int
    301 pl011parity(Uart *up, int mode)
    302 {
    303 	unsigned lcr_h;
    304 
    305 	lcr_h = plin(up, UARTLCR_H);
    306 	lcr_h &= ~(SPS | EPS | PEN);
    307 
    308 	switch (mode) {
    309 	case OPARITY:
    310 		lcr_h |= PEN;
    311 		break;
    312 	case EPARITY:
    313 		lcr_h |= PEN | EPS;
    314 		break;
    315 	case NPARITY:
    316 		break;
    317 	default:
    318 		return -1;
    319 	}
    320 
    321 	plout(up, UARTLCR_H, lcr_h);
    322 
    323 	return 0;
    324 }
    325 
    326 static int
    327 pl011stop(Uart *up, int nbits)
    328 {
    329 	unsigned lcr_h;
    330 
    331 	lcr_h = plin(up, UARTLCR_H);
    332 	lcr_h &= ~STP2;
    333 
    334 	switch (nbits) {
    335 	case 1:
    336 		break;
    337 	case 2:
    338 		lcr_h |= STP2;
    339 		break;
    340 	default:
    341 		return -1;
    342 	}
    343 
    344 	up->nbits = nbits;
    345 	plout(up, UARTLCR_H, lcr_h);
    346 
    347 	return 0;
    348 }
    349 
    350 static int
    351 pl011obey(Uart *up, int signal, int ena)
    352 {
    353 	unsigned cr;
    354 
    355 	cr = plin(up, UARTCR);
    356 	ena = (ena != 0);
    357 
    358 	switch (signal) {
    359 	case SIG_CTS:
    360 		cr &= ~CTSEN;
    361 		if (ena)
    362 			cr |= CTSEN;
    363 		up->ctsflow = ena;
    364 		break;
    365 	default:
    366 		return -1;
    367 	}
    368 
    369 	plout(up, UARTCR, cr);
    370 
    371 	return 0;
    372 }
    373 
    374 static int
    375 pl011status(Uart *up, struct uartstat *st)
    376 {
    377 	return 0;
    378 }
    379 
    380 Uartphy pl011phy = {
    381 	.name = "pl011",
    382 	.init = pl011init,
    383 	.setbauds = setbauds,
    384 	.read = pl011read,
    385 	.write = pl011write,
    386 	.signal = pl011signal,
    387 	.flush = pl011flush,
    388 	.setfifo = pl011fifo,
    389 	.numbits = pl011bits,
    390 	.parity = pl011parity,
    391 	.bitstop = pl011stop,
    392 	.obey  = pl011obey,
    393 	.status = pl011status,
    394 };