diff options
author | David Daney <ddaney@caviumnetworks.com> | 2009-01-02 08:49:47 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-01-02 13:19:43 -0500 |
commit | 7d6a07d123b62bf4fa71867420c23da3ca36c995 (patch) | |
tree | ccb554b8bf86b9cf1b4f6bcd88745e0c5cb1793e | |
parent | b430428a188e8a434325e251d0704af4b88b4711 (diff) |
8250: Serial driver changes to support future Cavium OCTEON serial patches.
In order to use Cavium OCTEON specific serial i/o drivers, we first
patch the 8250 driver to use replaceable I/O functions. Compatible
I/O functions are added for existing iotypeS.
An added benefit of this change is that it makes it easy to factor
some of the existing special cases out to board/SOC specific support
code.
The alternative is to load up 8250.c with a bunch of OCTEON specific
iotype code and bug work-arounds.
Signed-off-by: David Daney <ddaney@caviumnetworks.com>
Signed-off-by: Tomaso Paoletti <tpaoletti@caviumnetworks.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Alan Cox <alan@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | drivers/serial/8250.c | 194 | ||||
-rw-r--r-- | include/linux/serial_8250.h | 2 | ||||
-rw-r--r-- | include/linux/serial_core.h | 2 |
3 files changed, 140 insertions, 58 deletions
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 8e28750a4058..849af9d21feb 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c | |||
@@ -303,16 +303,16 @@ static const u8 au_io_out_map[] = { | |||
303 | }; | 303 | }; |
304 | 304 | ||
305 | /* sane hardware needs no mapping */ | 305 | /* sane hardware needs no mapping */ |
306 | static inline int map_8250_in_reg(struct uart_8250_port *up, int offset) | 306 | static inline int map_8250_in_reg(struct uart_port *p, int offset) |
307 | { | 307 | { |
308 | if (up->port.iotype != UPIO_AU) | 308 | if (p->iotype != UPIO_AU) |
309 | return offset; | 309 | return offset; |
310 | return au_io_in_map[offset]; | 310 | return au_io_in_map[offset]; |
311 | } | 311 | } |
312 | 312 | ||
313 | static inline int map_8250_out_reg(struct uart_8250_port *up, int offset) | 313 | static inline int map_8250_out_reg(struct uart_port *p, int offset) |
314 | { | 314 | { |
315 | if (up->port.iotype != UPIO_AU) | 315 | if (p->iotype != UPIO_AU) |
316 | return offset; | 316 | return offset; |
317 | return au_io_out_map[offset]; | 317 | return au_io_out_map[offset]; |
318 | } | 318 | } |
@@ -341,16 +341,16 @@ static const u8 | |||
341 | [UART_SCR] = 0x2c | 341 | [UART_SCR] = 0x2c |
342 | }; | 342 | }; |
343 | 343 | ||
344 | static inline int map_8250_in_reg(struct uart_8250_port *up, int offset) | 344 | static inline int map_8250_in_reg(struct uart_port *p, int offset) |
345 | { | 345 | { |
346 | if (up->port.iotype != UPIO_RM9000) | 346 | if (p->iotype != UPIO_RM9000) |
347 | return offset; | 347 | return offset; |
348 | return regmap_in[offset]; | 348 | return regmap_in[offset]; |
349 | } | 349 | } |
350 | 350 | ||
351 | static inline int map_8250_out_reg(struct uart_8250_port *up, int offset) | 351 | static inline int map_8250_out_reg(struct uart_port *p, int offset) |
352 | { | 352 | { |
353 | if (up->port.iotype != UPIO_RM9000) | 353 | if (p->iotype != UPIO_RM9000) |
354 | return offset; | 354 | return offset; |
355 | return regmap_out[offset]; | 355 | return regmap_out[offset]; |
356 | } | 356 | } |
@@ -363,108 +363,170 @@ static inline int map_8250_out_reg(struct uart_8250_port *up, int offset) | |||
363 | 363 | ||
364 | #endif | 364 | #endif |
365 | 365 | ||
366 | static unsigned int serial_in(struct uart_8250_port *up, int offset) | 366 | static unsigned int hub6_serial_in(struct uart_port *p, int offset) |
367 | { | 367 | { |
368 | unsigned int tmp; | 368 | offset = map_8250_in_reg(p, offset) << p->regshift; |
369 | offset = map_8250_in_reg(up, offset) << up->port.regshift; | 369 | outb(p->hub6 - 1 + offset, p->iobase); |
370 | return inb(p->iobase + 1); | ||
371 | } | ||
370 | 372 | ||
371 | switch (up->port.iotype) { | 373 | static void hub6_serial_out(struct uart_port *p, int offset, int value) |
372 | case UPIO_HUB6: | 374 | { |
373 | outb(up->port.hub6 - 1 + offset, up->port.iobase); | 375 | offset = map_8250_out_reg(p, offset) << p->regshift; |
374 | return inb(up->port.iobase + 1); | 376 | outb(p->hub6 - 1 + offset, p->iobase); |
377 | outb(value, p->iobase + 1); | ||
378 | } | ||
375 | 379 | ||
376 | case UPIO_MEM: | 380 | static unsigned int mem_serial_in(struct uart_port *p, int offset) |
377 | case UPIO_DWAPB: | 381 | { |
378 | return readb(up->port.membase + offset); | 382 | offset = map_8250_in_reg(p, offset) << p->regshift; |
383 | return readb(p->membase + offset); | ||
384 | } | ||
379 | 385 | ||
380 | case UPIO_RM9000: | 386 | static void mem_serial_out(struct uart_port *p, int offset, int value) |
381 | case UPIO_MEM32: | 387 | { |
382 | return readl(up->port.membase + offset); | 388 | offset = map_8250_out_reg(p, offset) << p->regshift; |
389 | writeb(value, p->membase + offset); | ||
390 | } | ||
391 | |||
392 | static void mem32_serial_out(struct uart_port *p, int offset, int value) | ||
393 | { | ||
394 | offset = map_8250_out_reg(p, offset) << p->regshift; | ||
395 | writel(value, p->membase + offset); | ||
396 | } | ||
397 | |||
398 | static unsigned int mem32_serial_in(struct uart_port *p, int offset) | ||
399 | { | ||
400 | offset = map_8250_in_reg(p, offset) << p->regshift; | ||
401 | return readl(p->membase + offset); | ||
402 | } | ||
383 | 403 | ||
384 | #ifdef CONFIG_SERIAL_8250_AU1X00 | 404 | #ifdef CONFIG_SERIAL_8250_AU1X00 |
385 | case UPIO_AU: | 405 | static unsigned int au_serial_in(struct uart_port *p, int offset) |
386 | return __raw_readl(up->port.membase + offset); | 406 | { |
407 | offset = map_8250_in_reg(p, offset) << p->regshift; | ||
408 | return __raw_readl(p->membase + offset); | ||
409 | } | ||
410 | |||
411 | static void au_serial_out(struct uart_port *p, int offset, int value) | ||
412 | { | ||
413 | offset = map_8250_out_reg(p, offset) << p->regshift; | ||
414 | __raw_writel(value, p->membase + offset); | ||
415 | } | ||
387 | #endif | 416 | #endif |
388 | 417 | ||
389 | case UPIO_TSI: | 418 | static unsigned int tsi_serial_in(struct uart_port *p, int offset) |
390 | if (offset == UART_IIR) { | 419 | { |
391 | tmp = readl(up->port.membase + (UART_IIR & ~3)); | 420 | unsigned int tmp; |
392 | return (tmp >> 16) & 0xff; /* UART_IIR % 4 == 2 */ | 421 | offset = map_8250_in_reg(p, offset) << p->regshift; |
393 | } else | 422 | if (offset == UART_IIR) { |
394 | return readb(up->port.membase + offset); | 423 | tmp = readl(p->membase + (UART_IIR & ~3)); |
424 | return (tmp >> 16) & 0xff; /* UART_IIR % 4 == 2 */ | ||
425 | } else | ||
426 | return readb(p->membase + offset); | ||
427 | } | ||
395 | 428 | ||
396 | default: | 429 | static void tsi_serial_out(struct uart_port *p, int offset, int value) |
397 | return inb(up->port.iobase + offset); | 430 | { |
398 | } | 431 | offset = map_8250_out_reg(p, offset) << p->regshift; |
432 | if (!((offset == UART_IER) && (value & UART_IER_UUE))) | ||
433 | writeb(value, p->membase + offset); | ||
399 | } | 434 | } |
400 | 435 | ||
401 | static void | 436 | static void dwapb_serial_out(struct uart_port *p, int offset, int value) |
402 | serial_out(struct uart_8250_port *up, int offset, int value) | ||
403 | { | 437 | { |
404 | /* Save the offset before it's remapped */ | ||
405 | int save_offset = offset; | 438 | int save_offset = offset; |
406 | offset = map_8250_out_reg(up, offset) << up->port.regshift; | 439 | offset = map_8250_out_reg(p, offset) << p->regshift; |
440 | /* Save the LCR value so it can be re-written when a | ||
441 | * Busy Detect interrupt occurs. */ | ||
442 | if (save_offset == UART_LCR) { | ||
443 | struct uart_8250_port *up = (struct uart_8250_port *)p; | ||
444 | up->lcr = value; | ||
445 | } | ||
446 | writeb(value, p->membase + offset); | ||
447 | /* Read the IER to ensure any interrupt is cleared before | ||
448 | * returning from ISR. */ | ||
449 | if (save_offset == UART_TX || save_offset == UART_IER) | ||
450 | value = p->serial_in(p, UART_IER); | ||
451 | } | ||
407 | 452 | ||
408 | switch (up->port.iotype) { | 453 | static unsigned int io_serial_in(struct uart_port *p, int offset) |
454 | { | ||
455 | offset = map_8250_in_reg(p, offset) << p->regshift; | ||
456 | return inb(p->iobase + offset); | ||
457 | } | ||
458 | |||
459 | static void io_serial_out(struct uart_port *p, int offset, int value) | ||
460 | { | ||
461 | offset = map_8250_out_reg(p, offset) << p->regshift; | ||
462 | outb(value, p->iobase + offset); | ||
463 | } | ||
464 | |||
465 | static void set_io_from_upio(struct uart_port *p) | ||
466 | { | ||
467 | switch (p->iotype) { | ||
409 | case UPIO_HUB6: | 468 | case UPIO_HUB6: |
410 | outb(up->port.hub6 - 1 + offset, up->port.iobase); | 469 | p->serial_in = hub6_serial_in; |
411 | outb(value, up->port.iobase + 1); | 470 | p->serial_out = hub6_serial_out; |
412 | break; | 471 | break; |
413 | 472 | ||
414 | case UPIO_MEM: | 473 | case UPIO_MEM: |
415 | writeb(value, up->port.membase + offset); | 474 | p->serial_in = mem_serial_in; |
475 | p->serial_out = mem_serial_out; | ||
416 | break; | 476 | break; |
417 | 477 | ||
418 | case UPIO_RM9000: | 478 | case UPIO_RM9000: |
419 | case UPIO_MEM32: | 479 | case UPIO_MEM32: |
420 | writel(value, up->port.membase + offset); | 480 | p->serial_in = mem32_serial_in; |
481 | p->serial_out = mem32_serial_out; | ||
421 | break; | 482 | break; |
422 | 483 | ||
423 | #ifdef CONFIG_SERIAL_8250_AU1X00 | 484 | #ifdef CONFIG_SERIAL_8250_AU1X00 |
424 | case UPIO_AU: | 485 | case UPIO_AU: |
425 | __raw_writel(value, up->port.membase + offset); | 486 | p->serial_in = au_serial_in; |
487 | p->serial_out = au_serial_out; | ||
426 | break; | 488 | break; |
427 | #endif | 489 | #endif |
428 | case UPIO_TSI: | 490 | case UPIO_TSI: |
429 | if (!((offset == UART_IER) && (value & UART_IER_UUE))) | 491 | p->serial_in = tsi_serial_in; |
430 | writeb(value, up->port.membase + offset); | 492 | p->serial_out = tsi_serial_out; |
431 | break; | 493 | break; |
432 | 494 | ||
433 | case UPIO_DWAPB: | 495 | case UPIO_DWAPB: |
434 | /* Save the LCR value so it can be re-written when a | 496 | p->serial_in = mem_serial_in; |
435 | * Busy Detect interrupt occurs. */ | 497 | p->serial_out = dwapb_serial_out; |
436 | if (save_offset == UART_LCR) | ||
437 | up->lcr = value; | ||
438 | writeb(value, up->port.membase + offset); | ||
439 | /* Read the IER to ensure any interrupt is cleared before | ||
440 | * returning from ISR. */ | ||
441 | if (save_offset == UART_TX || save_offset == UART_IER) | ||
442 | value = serial_in(up, UART_IER); | ||
443 | break; | 498 | break; |
444 | 499 | ||
445 | default: | 500 | default: |
446 | outb(value, up->port.iobase + offset); | 501 | p->serial_in = io_serial_in; |
502 | p->serial_out = io_serial_out; | ||
503 | break; | ||
447 | } | 504 | } |
448 | } | 505 | } |
449 | 506 | ||
450 | static void | 507 | static void |
451 | serial_out_sync(struct uart_8250_port *up, int offset, int value) | 508 | serial_out_sync(struct uart_8250_port *up, int offset, int value) |
452 | { | 509 | { |
453 | switch (up->port.iotype) { | 510 | struct uart_port *p = &up->port; |
511 | switch (p->iotype) { | ||
454 | case UPIO_MEM: | 512 | case UPIO_MEM: |
455 | case UPIO_MEM32: | 513 | case UPIO_MEM32: |
456 | #ifdef CONFIG_SERIAL_8250_AU1X00 | 514 | #ifdef CONFIG_SERIAL_8250_AU1X00 |
457 | case UPIO_AU: | 515 | case UPIO_AU: |
458 | #endif | 516 | #endif |
459 | case UPIO_DWAPB: | 517 | case UPIO_DWAPB: |
460 | serial_out(up, offset, value); | 518 | p->serial_out(p, offset, value); |
461 | serial_in(up, UART_LCR); /* safe, no side-effects */ | 519 | p->serial_in(p, UART_LCR); /* safe, no side-effects */ |
462 | break; | 520 | break; |
463 | default: | 521 | default: |
464 | serial_out(up, offset, value); | 522 | p->serial_out(p, offset, value); |
465 | } | 523 | } |
466 | } | 524 | } |
467 | 525 | ||
526 | #define serial_in(up, offset) \ | ||
527 | (up->port.serial_in(&(up)->port, (offset))) | ||
528 | #define serial_out(up, offset, value) \ | ||
529 | (up->port.serial_out(&(up)->port, (offset), (value))) | ||
468 | /* | 530 | /* |
469 | * We used to support using pause I/O for certain machines. We | 531 | * We used to support using pause I/O for certain machines. We |
470 | * haven't supported this for a while, but just in case it's badly | 532 | * haven't supported this for a while, but just in case it's badly |
@@ -2576,6 +2638,7 @@ static void __init serial8250_isa_init_ports(void) | |||
2576 | up->port.membase = old_serial_port[i].iomem_base; | 2638 | up->port.membase = old_serial_port[i].iomem_base; |
2577 | up->port.iotype = old_serial_port[i].io_type; | 2639 | up->port.iotype = old_serial_port[i].io_type; |
2578 | up->port.regshift = old_serial_port[i].iomem_reg_shift; | 2640 | up->port.regshift = old_serial_port[i].iomem_reg_shift; |
2641 | set_io_from_upio(&up->port); | ||
2579 | if (share_irqs) | 2642 | if (share_irqs) |
2580 | up->port.flags |= UPF_SHARE_IRQ; | 2643 | up->port.flags |= UPF_SHARE_IRQ; |
2581 | } | 2644 | } |
@@ -2769,6 +2832,13 @@ int __init early_serial_setup(struct uart_port *port) | |||
2769 | p->flags = port->flags; | 2832 | p->flags = port->flags; |
2770 | p->mapbase = port->mapbase; | 2833 | p->mapbase = port->mapbase; |
2771 | p->private_data = port->private_data; | 2834 | p->private_data = port->private_data; |
2835 | |||
2836 | set_io_from_upio(p); | ||
2837 | if (port->serial_in) | ||
2838 | p->serial_in = port->serial_in; | ||
2839 | if (port->serial_out) | ||
2840 | p->serial_out = port->serial_out; | ||
2841 | |||
2772 | return 0; | 2842 | return 0; |
2773 | } | 2843 | } |
2774 | 2844 | ||
@@ -2833,6 +2903,8 @@ static int __devinit serial8250_probe(struct platform_device *dev) | |||
2833 | port.mapbase = p->mapbase; | 2903 | port.mapbase = p->mapbase; |
2834 | port.hub6 = p->hub6; | 2904 | port.hub6 = p->hub6; |
2835 | port.private_data = p->private_data; | 2905 | port.private_data = p->private_data; |
2906 | port.serial_in = p->serial_in; | ||
2907 | port.serial_out = p->serial_out; | ||
2836 | port.dev = &dev->dev; | 2908 | port.dev = &dev->dev; |
2837 | if (share_irqs) | 2909 | if (share_irqs) |
2838 | port.flags |= UPF_SHARE_IRQ; | 2910 | port.flags |= UPF_SHARE_IRQ; |
@@ -2986,6 +3058,12 @@ int serial8250_register_port(struct uart_port *port) | |||
2986 | uart->port.private_data = port->private_data; | 3058 | uart->port.private_data = port->private_data; |
2987 | if (port->dev) | 3059 | if (port->dev) |
2988 | uart->port.dev = port->dev; | 3060 | uart->port.dev = port->dev; |
3061 | set_io_from_upio(&uart->port); | ||
3062 | /* Possibly override default I/O functions. */ | ||
3063 | if (port->serial_in) | ||
3064 | uart->port.serial_in = port->serial_in; | ||
3065 | if (port->serial_out) | ||
3066 | uart->port.serial_out = port->serial_out; | ||
2989 | 3067 | ||
2990 | ret = uart_add_one_port(&serial8250_reg, &uart->port); | 3068 | ret = uart_add_one_port(&serial8250_reg, &uart->port); |
2991 | if (ret == 0) | 3069 | if (ret == 0) |
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index 3d37c94abbc8..77d83d929f2c 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h | |||
@@ -28,6 +28,8 @@ struct plat_serial8250_port { | |||
28 | unsigned char iotype; /* UPIO_* */ | 28 | unsigned char iotype; /* UPIO_* */ |
29 | unsigned char hub6; | 29 | unsigned char hub6; |
30 | upf_t flags; /* UPF_* flags */ | 30 | upf_t flags; /* UPF_* flags */ |
31 | unsigned int (*serial_in)(struct uart_port *, int); | ||
32 | void (*serial_out)(struct uart_port *, int, int); | ||
31 | }; | 33 | }; |
32 | 34 | ||
33 | /* | 35 | /* |
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 2395969faa04..60061f44f3d8 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h | |||
@@ -248,6 +248,8 @@ struct uart_port { | |||
248 | spinlock_t lock; /* port lock */ | 248 | spinlock_t lock; /* port lock */ |
249 | unsigned long iobase; /* in/out[bwl] */ | 249 | unsigned long iobase; /* in/out[bwl] */ |
250 | unsigned char __iomem *membase; /* read/write[bwl] */ | 250 | unsigned char __iomem *membase; /* read/write[bwl] */ |
251 | unsigned int (*serial_in)(struct uart_port *, int); | ||
252 | void (*serial_out)(struct uart_port *, int, int); | ||
251 | unsigned int irq; /* irq number */ | 253 | unsigned int irq; /* irq number */ |
252 | unsigned int uartclk; /* base uart clock */ | 254 | unsigned int uartclk; /* base uart clock */ |
253 | unsigned int fifosize; /* tx fifo size */ | 255 | unsigned int fifosize; /* tx fifo size */ |