diff options
author | Stephen Boyd <sboyd@codeaurora.org> | 2014-01-14 15:34:55 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-02-12 14:34:23 -0500 |
commit | f7e54d7ad743a0cf0e400ac185036df6a592567c (patch) | |
tree | 8a2be5d50787660b58026c8f8366a9065c9d5d60 /drivers/tty/serial/msm_serial.c | |
parent | b28a960c42fcd9cfc987441fa6d1c1a471f0f9ed (diff) |
msm_serial: Add support for poll_{get,put}_char()
Implement the polling functionality for the MSM serial driver.
This allows us to use KGDB on this hardware.
Cc: David Brown <davidb@codeaurora.org>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/serial/msm_serial.c')
-rw-r--r-- | drivers/tty/serial/msm_serial.c | 140 |
1 files changed, 137 insertions, 3 deletions
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index b5d779cd3c2b..053b98eb46c8 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c | |||
@@ -39,6 +39,13 @@ | |||
39 | 39 | ||
40 | #include "msm_serial.h" | 40 | #include "msm_serial.h" |
41 | 41 | ||
42 | enum { | ||
43 | UARTDM_1P1 = 1, | ||
44 | UARTDM_1P2, | ||
45 | UARTDM_1P3, | ||
46 | UARTDM_1P4, | ||
47 | }; | ||
48 | |||
42 | struct msm_port { | 49 | struct msm_port { |
43 | struct uart_port uart; | 50 | struct uart_port uart; |
44 | char name[16]; | 51 | char name[16]; |
@@ -309,6 +316,8 @@ static unsigned int msm_get_mctrl(struct uart_port *port) | |||
309 | 316 | ||
310 | static void msm_reset(struct uart_port *port) | 317 | static void msm_reset(struct uart_port *port) |
311 | { | 318 | { |
319 | struct msm_port *msm_port = UART_TO_MSM(port); | ||
320 | |||
312 | /* reset everything */ | 321 | /* reset everything */ |
313 | msm_write(port, UART_CR_CMD_RESET_RX, UART_CR); | 322 | msm_write(port, UART_CR_CMD_RESET_RX, UART_CR); |
314 | msm_write(port, UART_CR_CMD_RESET_TX, UART_CR); | 323 | msm_write(port, UART_CR_CMD_RESET_TX, UART_CR); |
@@ -316,6 +325,10 @@ static void msm_reset(struct uart_port *port) | |||
316 | msm_write(port, UART_CR_CMD_RESET_BREAK_INT, UART_CR); | 325 | msm_write(port, UART_CR_CMD_RESET_BREAK_INT, UART_CR); |
317 | msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR); | 326 | msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR); |
318 | msm_write(port, UART_CR_CMD_SET_RFR, UART_CR); | 327 | msm_write(port, UART_CR_CMD_SET_RFR, UART_CR); |
328 | |||
329 | /* Disable DM modes */ | ||
330 | if (msm_port->is_uartdm) | ||
331 | msm_write(port, 0, UARTDM_DMEN); | ||
319 | } | 332 | } |
320 | 333 | ||
321 | static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl) | 334 | static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl) |
@@ -711,6 +724,117 @@ static void msm_power(struct uart_port *port, unsigned int state, | |||
711 | } | 724 | } |
712 | } | 725 | } |
713 | 726 | ||
727 | #ifdef CONFIG_CONSOLE_POLL | ||
728 | static int msm_poll_init(struct uart_port *port) | ||
729 | { | ||
730 | struct msm_port *msm_port = UART_TO_MSM(port); | ||
731 | |||
732 | /* Enable single character mode on RX FIFO */ | ||
733 | if (msm_port->is_uartdm >= UARTDM_1P4) | ||
734 | msm_write(port, UARTDM_DMEN_RX_SC_ENABLE, UARTDM_DMEN); | ||
735 | |||
736 | return 0; | ||
737 | } | ||
738 | |||
739 | static int msm_poll_get_char_single(struct uart_port *port) | ||
740 | { | ||
741 | struct msm_port *msm_port = UART_TO_MSM(port); | ||
742 | unsigned int rf_reg = msm_port->is_uartdm ? UARTDM_RF : UART_RF; | ||
743 | |||
744 | if (!(msm_read(port, UART_SR) & UART_SR_RX_READY)) | ||
745 | return NO_POLL_CHAR; | ||
746 | else | ||
747 | return msm_read(port, rf_reg) & 0xff; | ||
748 | } | ||
749 | |||
750 | static int msm_poll_get_char_dm_1p3(struct uart_port *port) | ||
751 | { | ||
752 | int c; | ||
753 | static u32 slop; | ||
754 | static int count; | ||
755 | unsigned char *sp = (unsigned char *)&slop; | ||
756 | |||
757 | /* Check if a previous read had more than one char */ | ||
758 | if (count) { | ||
759 | c = sp[sizeof(slop) - count]; | ||
760 | count--; | ||
761 | /* Or if FIFO is empty */ | ||
762 | } else if (!(msm_read(port, UART_SR) & UART_SR_RX_READY)) { | ||
763 | /* | ||
764 | * If RX packing buffer has less than a word, force stale to | ||
765 | * push contents into RX FIFO | ||
766 | */ | ||
767 | count = msm_read(port, UARTDM_RXFS); | ||
768 | count = (count >> UARTDM_RXFS_BUF_SHIFT) & UARTDM_RXFS_BUF_MASK; | ||
769 | if (count) { | ||
770 | msm_write(port, UART_CR_CMD_FORCE_STALE, UART_CR); | ||
771 | slop = msm_read(port, UARTDM_RF); | ||
772 | c = sp[0]; | ||
773 | count--; | ||
774 | } else { | ||
775 | c = NO_POLL_CHAR; | ||
776 | } | ||
777 | /* FIFO has a word */ | ||
778 | } else { | ||
779 | slop = msm_read(port, UARTDM_RF); | ||
780 | c = sp[0]; | ||
781 | count = sizeof(slop) - 1; | ||
782 | } | ||
783 | |||
784 | return c; | ||
785 | } | ||
786 | |||
787 | static int msm_poll_get_char(struct uart_port *port) | ||
788 | { | ||
789 | u32 imr; | ||
790 | int c; | ||
791 | struct msm_port *msm_port = UART_TO_MSM(port); | ||
792 | |||
793 | /* Disable all interrupts */ | ||
794 | imr = msm_read(port, UART_IMR); | ||
795 | msm_write(port, 0, UART_IMR); | ||
796 | |||
797 | if (msm_port->is_uartdm == UARTDM_1P3) | ||
798 | c = msm_poll_get_char_dm_1p3(port); | ||
799 | else | ||
800 | c = msm_poll_get_char_single(port); | ||
801 | |||
802 | /* Enable interrupts */ | ||
803 | msm_write(port, imr, UART_IMR); | ||
804 | |||
805 | return c; | ||
806 | } | ||
807 | |||
808 | static void msm_poll_put_char(struct uart_port *port, unsigned char c) | ||
809 | { | ||
810 | u32 imr; | ||
811 | struct msm_port *msm_port = UART_TO_MSM(port); | ||
812 | |||
813 | /* Disable all interrupts */ | ||
814 | imr = msm_read(port, UART_IMR); | ||
815 | msm_write(port, 0, UART_IMR); | ||
816 | |||
817 | if (msm_port->is_uartdm) | ||
818 | reset_dm_count(port, 1); | ||
819 | |||
820 | /* Wait until FIFO is empty */ | ||
821 | while (!(msm_read(port, UART_SR) & UART_SR_TX_READY)) | ||
822 | cpu_relax(); | ||
823 | |||
824 | /* Write a character */ | ||
825 | msm_write(port, c, msm_port->is_uartdm ? UARTDM_TF : UART_TF); | ||
826 | |||
827 | /* Wait until FIFO is empty */ | ||
828 | while (!(msm_read(port, UART_SR) & UART_SR_TX_READY)) | ||
829 | cpu_relax(); | ||
830 | |||
831 | /* Enable interrupts */ | ||
832 | msm_write(port, imr, UART_IMR); | ||
833 | |||
834 | return; | ||
835 | } | ||
836 | #endif | ||
837 | |||
714 | static struct uart_ops msm_uart_pops = { | 838 | static struct uart_ops msm_uart_pops = { |
715 | .tx_empty = msm_tx_empty, | 839 | .tx_empty = msm_tx_empty, |
716 | .set_mctrl = msm_set_mctrl, | 840 | .set_mctrl = msm_set_mctrl, |
@@ -729,6 +853,11 @@ static struct uart_ops msm_uart_pops = { | |||
729 | .config_port = msm_config_port, | 853 | .config_port = msm_config_port, |
730 | .verify_port = msm_verify_port, | 854 | .verify_port = msm_verify_port, |
731 | .pm = msm_power, | 855 | .pm = msm_power, |
856 | #ifdef CONFIG_CONSOLE_POLL | ||
857 | .poll_init = msm_poll_init, | ||
858 | .poll_get_char = msm_poll_get_char, | ||
859 | .poll_put_char = msm_poll_put_char, | ||
860 | #endif | ||
732 | }; | 861 | }; |
733 | 862 | ||
734 | static struct msm_port msm_uart_ports[] = { | 863 | static struct msm_port msm_uart_ports[] = { |
@@ -900,7 +1029,10 @@ static struct uart_driver msm_uart_driver = { | |||
900 | static atomic_t msm_uart_next_id = ATOMIC_INIT(0); | 1029 | static atomic_t msm_uart_next_id = ATOMIC_INIT(0); |
901 | 1030 | ||
902 | static const struct of_device_id msm_uartdm_table[] = { | 1031 | static const struct of_device_id msm_uartdm_table[] = { |
903 | { .compatible = "qcom,msm-uartdm" }, | 1032 | { .compatible = "qcom,msm-uartdm-v1.1", .data = (void *)UARTDM_1P1 }, |
1033 | { .compatible = "qcom,msm-uartdm-v1.2", .data = (void *)UARTDM_1P2 }, | ||
1034 | { .compatible = "qcom,msm-uartdm-v1.3", .data = (void *)UARTDM_1P3 }, | ||
1035 | { .compatible = "qcom,msm-uartdm-v1.4", .data = (void *)UARTDM_1P4 }, | ||
904 | { } | 1036 | { } |
905 | }; | 1037 | }; |
906 | 1038 | ||
@@ -909,6 +1041,7 @@ static int __init msm_serial_probe(struct platform_device *pdev) | |||
909 | struct msm_port *msm_port; | 1041 | struct msm_port *msm_port; |
910 | struct resource *resource; | 1042 | struct resource *resource; |
911 | struct uart_port *port; | 1043 | struct uart_port *port; |
1044 | const struct of_device_id *id; | ||
912 | int irq; | 1045 | int irq; |
913 | 1046 | ||
914 | if (pdev->id == -1) | 1047 | if (pdev->id == -1) |
@@ -923,8 +1056,9 @@ static int __init msm_serial_probe(struct platform_device *pdev) | |||
923 | port->dev = &pdev->dev; | 1056 | port->dev = &pdev->dev; |
924 | msm_port = UART_TO_MSM(port); | 1057 | msm_port = UART_TO_MSM(port); |
925 | 1058 | ||
926 | if (of_match_device(msm_uartdm_table, &pdev->dev)) | 1059 | id = of_match_device(msm_uartdm_table, &pdev->dev); |
927 | msm_port->is_uartdm = 1; | 1060 | if (id) |
1061 | msm_port->is_uartdm = (unsigned long)id->data; | ||
928 | else | 1062 | else |
929 | msm_port->is_uartdm = 0; | 1063 | msm_port->is_uartdm = 0; |
930 | 1064 | ||