diff options
author | Tomi Valkeinen <tomi.valkeinen@ti.com> | 2011-03-02 07:47:04 -0500 |
---|---|---|
committer | Tomi Valkeinen <tomi.valkeinen@ti.com> | 2011-03-15 04:54:18 -0400 |
commit | 4ae2ddddf44cd9f73def2dbdb68c6859072262ff (patch) | |
tree | e35ffc1b9fbc8529d7e0f2702e7717caa7731b44 /drivers/video/omap2/dss | |
parent | 69b281a61442f97e8df14babc9bb6a28624886b1 (diff) |
OMAP: DSS2: DSI: Add ISR support
Add generic ISR support for DSI interrupts. ISRs can be used instead of
custom hooks in the interrupt handler.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Diffstat (limited to 'drivers/video/omap2/dss')
-rw-r--r-- | drivers/video/omap2/dss/dsi.c | 329 |
1 files changed, 304 insertions, 25 deletions
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index b6c08a6f2da1..8613ec489410 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c | |||
@@ -185,6 +185,16 @@ struct dsi_reg { u16 idx; }; | |||
185 | #define DSI_DT_RX_SHORT_READ_1 0x21 | 185 | #define DSI_DT_RX_SHORT_READ_1 0x21 |
186 | #define DSI_DT_RX_SHORT_READ_2 0x22 | 186 | #define DSI_DT_RX_SHORT_READ_2 0x22 |
187 | 187 | ||
188 | typedef void (*omap_dsi_isr_t) (void *arg, u32 mask); | ||
189 | |||
190 | #define DSI_MAX_NR_ISRS 2 | ||
191 | |||
192 | struct dsi_isr_data { | ||
193 | omap_dsi_isr_t isr; | ||
194 | void *arg; | ||
195 | u32 mask; | ||
196 | }; | ||
197 | |||
188 | enum fifo_size { | 198 | enum fifo_size { |
189 | DSI_FIFO_SIZE_0 = 0, | 199 | DSI_FIFO_SIZE_0 = 0, |
190 | DSI_FIFO_SIZE_32 = 1, | 200 | DSI_FIFO_SIZE_32 = 1, |
@@ -211,6 +221,12 @@ struct dsi_irq_stats { | |||
211 | unsigned cio_irqs[32]; | 221 | unsigned cio_irqs[32]; |
212 | }; | 222 | }; |
213 | 223 | ||
224 | struct dsi_isr_tables { | ||
225 | struct dsi_isr_data isr_table[DSI_MAX_NR_ISRS]; | ||
226 | struct dsi_isr_data isr_table_vc[4][DSI_MAX_NR_ISRS]; | ||
227 | struct dsi_isr_data isr_table_cio[DSI_MAX_NR_ISRS]; | ||
228 | }; | ||
229 | |||
214 | static struct | 230 | static struct |
215 | { | 231 | { |
216 | struct platform_device *pdev; | 232 | struct platform_device *pdev; |
@@ -236,6 +252,11 @@ static struct | |||
236 | struct completion bta_completion; | 252 | struct completion bta_completion; |
237 | void (*bta_callback)(void); | 253 | void (*bta_callback)(void); |
238 | 254 | ||
255 | spinlock_t irq_lock; | ||
256 | struct dsi_isr_tables isr_tables; | ||
257 | /* space for a copy used by the interrupt handler */ | ||
258 | struct dsi_isr_tables isr_tables_copy; | ||
259 | |||
239 | int update_channel; | 260 | int update_channel; |
240 | struct dsi_update_region update_region; | 261 | struct dsi_update_region update_region; |
241 | 262 | ||
@@ -532,16 +553,56 @@ static void dsi_handle_irq_errors(u32 irqstatus, u32 *vcstatus, u32 ciostatus) | |||
532 | } | 553 | } |
533 | } | 554 | } |
534 | 555 | ||
556 | static void dsi_call_isrs(struct dsi_isr_data *isr_array, | ||
557 | unsigned isr_array_size, u32 irqstatus) | ||
558 | { | ||
559 | struct dsi_isr_data *isr_data; | ||
560 | int i; | ||
561 | |||
562 | for (i = 0; i < isr_array_size; i++) { | ||
563 | isr_data = &isr_array[i]; | ||
564 | if (isr_data->isr && isr_data->mask & irqstatus) | ||
565 | isr_data->isr(isr_data->arg, irqstatus); | ||
566 | } | ||
567 | } | ||
568 | |||
569 | static void dsi_handle_isrs(struct dsi_isr_tables *isr_tables, | ||
570 | u32 irqstatus, u32 *vcstatus, u32 ciostatus) | ||
571 | { | ||
572 | int i; | ||
573 | |||
574 | dsi_call_isrs(isr_tables->isr_table, | ||
575 | ARRAY_SIZE(isr_tables->isr_table), | ||
576 | irqstatus); | ||
577 | |||
578 | for (i = 0; i < 4; ++i) { | ||
579 | if (vcstatus[i] == 0) | ||
580 | continue; | ||
581 | dsi_call_isrs(isr_tables->isr_table_vc[i], | ||
582 | ARRAY_SIZE(isr_tables->isr_table_vc[i]), | ||
583 | vcstatus[i]); | ||
584 | } | ||
585 | |||
586 | if (ciostatus != 0) | ||
587 | dsi_call_isrs(isr_tables->isr_table_cio, | ||
588 | ARRAY_SIZE(isr_tables->isr_table_cio), | ||
589 | ciostatus); | ||
590 | } | ||
591 | |||
535 | static irqreturn_t omap_dsi_irq_handler(int irq, void *arg) | 592 | static irqreturn_t omap_dsi_irq_handler(int irq, void *arg) |
536 | { | 593 | { |
537 | u32 irqstatus, vcstatus[4], ciostatus; | 594 | u32 irqstatus, vcstatus[4], ciostatus; |
538 | int i; | 595 | int i; |
539 | 596 | ||
597 | spin_lock(&dsi.irq_lock); | ||
598 | |||
540 | irqstatus = dsi_read_reg(DSI_IRQSTATUS); | 599 | irqstatus = dsi_read_reg(DSI_IRQSTATUS); |
541 | 600 | ||
542 | /* IRQ is not for us */ | 601 | /* IRQ is not for us */ |
543 | if (!irqstatus) | 602 | if (!irqstatus) { |
603 | spin_unlock(&dsi.irq_lock); | ||
544 | return IRQ_NONE; | 604 | return IRQ_NONE; |
605 | } | ||
545 | 606 | ||
546 | dsi_write_reg(DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK); | 607 | dsi_write_reg(DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK); |
547 | /* flush posted write */ | 608 | /* flush posted write */ |
@@ -587,6 +648,14 @@ static irqreturn_t omap_dsi_irq_handler(int irq, void *arg) | |||
587 | } | 648 | } |
588 | } | 649 | } |
589 | 650 | ||
651 | /* make a copy and unlock, so that isrs can unregister | ||
652 | * themselves */ | ||
653 | memcpy(&dsi.isr_tables_copy, &dsi.isr_tables, sizeof(dsi.isr_tables)); | ||
654 | |||
655 | spin_unlock(&dsi.irq_lock); | ||
656 | |||
657 | dsi_handle_isrs(&dsi.isr_tables_copy, irqstatus, vcstatus, ciostatus); | ||
658 | |||
590 | dsi_handle_irq_errors(irqstatus, vcstatus, ciostatus); | 659 | dsi_handle_irq_errors(irqstatus, vcstatus, ciostatus); |
591 | 660 | ||
592 | dsi_collect_irq_stats(irqstatus, vcstatus, ciostatus); | 661 | dsi_collect_irq_stats(irqstatus, vcstatus, ciostatus); |
@@ -594,42 +663,251 @@ static irqreturn_t omap_dsi_irq_handler(int irq, void *arg) | |||
594 | return IRQ_HANDLED; | 663 | return IRQ_HANDLED; |
595 | } | 664 | } |
596 | 665 | ||
597 | static void _dsi_initialize_irq(void) | 666 | /* dsi.irq_lock has to be locked by the caller */ |
667 | static void _omap_dsi_configure_irqs(struct dsi_isr_data *isr_array, | ||
668 | unsigned isr_array_size, u32 default_mask, | ||
669 | const struct dsi_reg enable_reg, | ||
670 | const struct dsi_reg status_reg) | ||
598 | { | 671 | { |
599 | u32 l; | 672 | struct dsi_isr_data *isr_data; |
673 | u32 mask; | ||
674 | u32 old_mask; | ||
600 | int i; | 675 | int i; |
601 | 676 | ||
602 | /* disable all interrupts */ | 677 | mask = default_mask; |
603 | dsi_write_reg(DSI_IRQENABLE, 0); | ||
604 | for (i = 0; i < 4; ++i) | ||
605 | dsi_write_reg(DSI_VC_IRQENABLE(i), 0); | ||
606 | dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE, 0); | ||
607 | 678 | ||
608 | /* clear interrupt status */ | 679 | for (i = 0; i < isr_array_size; i++) { |
609 | l = dsi_read_reg(DSI_IRQSTATUS); | 680 | isr_data = &isr_array[i]; |
610 | dsi_write_reg(DSI_IRQSTATUS, l & ~DSI_IRQ_CHANNEL_MASK); | ||
611 | 681 | ||
612 | for (i = 0; i < 4; ++i) { | 682 | if (isr_data->isr == NULL) |
613 | l = dsi_read_reg(DSI_VC_IRQSTATUS(i)); | 683 | continue; |
614 | dsi_write_reg(DSI_VC_IRQSTATUS(i), l); | 684 | |
685 | mask |= isr_data->mask; | ||
615 | } | 686 | } |
616 | 687 | ||
617 | l = dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS); | 688 | old_mask = dsi_read_reg(enable_reg); |
618 | dsi_write_reg(DSI_COMPLEXIO_IRQ_STATUS, l); | 689 | /* clear the irqstatus for newly enabled irqs */ |
690 | dsi_write_reg(status_reg, (mask ^ old_mask) & mask); | ||
691 | dsi_write_reg(enable_reg, mask); | ||
692 | |||
693 | /* flush posted writes */ | ||
694 | dsi_read_reg(enable_reg); | ||
695 | dsi_read_reg(status_reg); | ||
696 | } | ||
619 | 697 | ||
620 | /* enable error irqs */ | 698 | /* dsi.irq_lock has to be locked by the caller */ |
621 | l = DSI_IRQ_ERROR_MASK; | 699 | static void _omap_dsi_set_irqs(void) |
700 | { | ||
701 | u32 mask = DSI_IRQ_ERROR_MASK; | ||
622 | #ifdef DSI_CATCH_MISSING_TE | 702 | #ifdef DSI_CATCH_MISSING_TE |
623 | l |= DSI_IRQ_TE_TRIGGER; | 703 | mask |= DSI_IRQ_TE_TRIGGER; |
624 | #endif | 704 | #endif |
625 | dsi_write_reg(DSI_IRQENABLE, l); | 705 | _omap_dsi_configure_irqs(dsi.isr_tables.isr_table, |
706 | ARRAY_SIZE(dsi.isr_tables.isr_table), mask, | ||
707 | DSI_IRQENABLE, DSI_IRQSTATUS); | ||
708 | } | ||
626 | 709 | ||
627 | l = DSI_VC_IRQ_ERROR_MASK; | 710 | /* dsi.irq_lock has to be locked by the caller */ |
628 | for (i = 0; i < 4; ++i) | 711 | static void _omap_dsi_set_irqs_vc(int vc) |
629 | dsi_write_reg(DSI_VC_IRQENABLE(i), l); | 712 | { |
713 | _omap_dsi_configure_irqs(dsi.isr_tables.isr_table_vc[vc], | ||
714 | ARRAY_SIZE(dsi.isr_tables.isr_table_vc[vc]), | ||
715 | DSI_VC_IRQ_ERROR_MASK, | ||
716 | DSI_VC_IRQENABLE(vc), DSI_VC_IRQSTATUS(vc)); | ||
717 | } | ||
718 | |||
719 | /* dsi.irq_lock has to be locked by the caller */ | ||
720 | static void _omap_dsi_set_irqs_cio(void) | ||
721 | { | ||
722 | _omap_dsi_configure_irqs(dsi.isr_tables.isr_table_cio, | ||
723 | ARRAY_SIZE(dsi.isr_tables.isr_table_cio), | ||
724 | DSI_CIO_IRQ_ERROR_MASK, | ||
725 | DSI_COMPLEXIO_IRQ_ENABLE, DSI_COMPLEXIO_IRQ_STATUS); | ||
726 | } | ||
727 | |||
728 | static void _dsi_initialize_irq(void) | ||
729 | { | ||
730 | unsigned long flags; | ||
731 | int vc; | ||
732 | |||
733 | spin_lock_irqsave(&dsi.irq_lock, flags); | ||
734 | |||
735 | memset(&dsi.isr_tables, 0, sizeof(dsi.isr_tables)); | ||
736 | |||
737 | _omap_dsi_set_irqs(); | ||
738 | for (vc = 0; vc < 4; ++vc) | ||
739 | _omap_dsi_set_irqs_vc(vc); | ||
740 | _omap_dsi_set_irqs_cio(); | ||
741 | |||
742 | spin_unlock_irqrestore(&dsi.irq_lock, flags); | ||
743 | } | ||
630 | 744 | ||
631 | l = DSI_CIO_IRQ_ERROR_MASK; | 745 | static int _dsi_register_isr(omap_dsi_isr_t isr, void *arg, u32 mask, |
632 | dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE, l); | 746 | struct dsi_isr_data *isr_array, unsigned isr_array_size) |
747 | { | ||
748 | struct dsi_isr_data *isr_data; | ||
749 | int free_idx; | ||
750 | int i; | ||
751 | |||
752 | BUG_ON(isr == NULL); | ||
753 | |||
754 | /* check for duplicate entry and find a free slot */ | ||
755 | free_idx = -1; | ||
756 | for (i = 0; i < isr_array_size; i++) { | ||
757 | isr_data = &isr_array[i]; | ||
758 | |||
759 | if (isr_data->isr == isr && isr_data->arg == arg && | ||
760 | isr_data->mask == mask) { | ||
761 | return -EINVAL; | ||
762 | } | ||
763 | |||
764 | if (isr_data->isr == NULL && free_idx == -1) | ||
765 | free_idx = i; | ||
766 | } | ||
767 | |||
768 | if (free_idx == -1) | ||
769 | return -EBUSY; | ||
770 | |||
771 | isr_data = &isr_array[free_idx]; | ||
772 | isr_data->isr = isr; | ||
773 | isr_data->arg = arg; | ||
774 | isr_data->mask = mask; | ||
775 | |||
776 | return 0; | ||
777 | } | ||
778 | |||
779 | static int _dsi_unregister_isr(omap_dsi_isr_t isr, void *arg, u32 mask, | ||
780 | struct dsi_isr_data *isr_array, unsigned isr_array_size) | ||
781 | { | ||
782 | struct dsi_isr_data *isr_data; | ||
783 | int i; | ||
784 | |||
785 | for (i = 0; i < isr_array_size; i++) { | ||
786 | isr_data = &isr_array[i]; | ||
787 | if (isr_data->isr != isr || isr_data->arg != arg || | ||
788 | isr_data->mask != mask) | ||
789 | continue; | ||
790 | |||
791 | isr_data->isr = NULL; | ||
792 | isr_data->arg = NULL; | ||
793 | isr_data->mask = 0; | ||
794 | |||
795 | return 0; | ||
796 | } | ||
797 | |||
798 | return -EINVAL; | ||
799 | } | ||
800 | |||
801 | static int dsi_register_isr(omap_dsi_isr_t isr, void *arg, u32 mask) | ||
802 | { | ||
803 | unsigned long flags; | ||
804 | int r; | ||
805 | |||
806 | spin_lock_irqsave(&dsi.irq_lock, flags); | ||
807 | |||
808 | r = _dsi_register_isr(isr, arg, mask, dsi.isr_tables.isr_table, | ||
809 | ARRAY_SIZE(dsi.isr_tables.isr_table)); | ||
810 | |||
811 | if (r == 0) | ||
812 | _omap_dsi_set_irqs(); | ||
813 | |||
814 | spin_unlock_irqrestore(&dsi.irq_lock, flags); | ||
815 | |||
816 | return r; | ||
817 | } | ||
818 | |||
819 | static int dsi_unregister_isr(omap_dsi_isr_t isr, void *arg, u32 mask) | ||
820 | { | ||
821 | unsigned long flags; | ||
822 | int r; | ||
823 | |||
824 | spin_lock_irqsave(&dsi.irq_lock, flags); | ||
825 | |||
826 | r = _dsi_unregister_isr(isr, arg, mask, dsi.isr_tables.isr_table, | ||
827 | ARRAY_SIZE(dsi.isr_tables.isr_table)); | ||
828 | |||
829 | if (r == 0) | ||
830 | _omap_dsi_set_irqs(); | ||
831 | |||
832 | spin_unlock_irqrestore(&dsi.irq_lock, flags); | ||
833 | |||
834 | return r; | ||
835 | } | ||
836 | |||
837 | static int dsi_register_isr_vc(int channel, omap_dsi_isr_t isr, void *arg, | ||
838 | u32 mask) | ||
839 | { | ||
840 | unsigned long flags; | ||
841 | int r; | ||
842 | |||
843 | spin_lock_irqsave(&dsi.irq_lock, flags); | ||
844 | |||
845 | r = _dsi_register_isr(isr, arg, mask, | ||
846 | dsi.isr_tables.isr_table_vc[channel], | ||
847 | ARRAY_SIZE(dsi.isr_tables.isr_table_vc[channel])); | ||
848 | |||
849 | if (r == 0) | ||
850 | _omap_dsi_set_irqs_vc(channel); | ||
851 | |||
852 | spin_unlock_irqrestore(&dsi.irq_lock, flags); | ||
853 | |||
854 | return r; | ||
855 | } | ||
856 | |||
857 | static int dsi_unregister_isr_vc(int channel, omap_dsi_isr_t isr, void *arg, | ||
858 | u32 mask) | ||
859 | { | ||
860 | unsigned long flags; | ||
861 | int r; | ||
862 | |||
863 | spin_lock_irqsave(&dsi.irq_lock, flags); | ||
864 | |||
865 | r = _dsi_unregister_isr(isr, arg, mask, | ||
866 | dsi.isr_tables.isr_table_vc[channel], | ||
867 | ARRAY_SIZE(dsi.isr_tables.isr_table_vc[channel])); | ||
868 | |||
869 | if (r == 0) | ||
870 | _omap_dsi_set_irqs_vc(channel); | ||
871 | |||
872 | spin_unlock_irqrestore(&dsi.irq_lock, flags); | ||
873 | |||
874 | return r; | ||
875 | } | ||
876 | |||
877 | static int dsi_register_isr_cio(omap_dsi_isr_t isr, void *arg, u32 mask) | ||
878 | { | ||
879 | unsigned long flags; | ||
880 | int r; | ||
881 | |||
882 | spin_lock_irqsave(&dsi.irq_lock, flags); | ||
883 | |||
884 | r = _dsi_register_isr(isr, arg, mask, dsi.isr_tables.isr_table_cio, | ||
885 | ARRAY_SIZE(dsi.isr_tables.isr_table_cio)); | ||
886 | |||
887 | if (r == 0) | ||
888 | _omap_dsi_set_irqs_cio(); | ||
889 | |||
890 | spin_unlock_irqrestore(&dsi.irq_lock, flags); | ||
891 | |||
892 | return r; | ||
893 | } | ||
894 | |||
895 | static int dsi_unregister_isr_cio(omap_dsi_isr_t isr, void *arg, u32 mask) | ||
896 | { | ||
897 | unsigned long flags; | ||
898 | int r; | ||
899 | |||
900 | spin_lock_irqsave(&dsi.irq_lock, flags); | ||
901 | |||
902 | r = _dsi_unregister_isr(isr, arg, mask, dsi.isr_tables.isr_table_cio, | ||
903 | ARRAY_SIZE(dsi.isr_tables.isr_table_cio)); | ||
904 | |||
905 | if (r == 0) | ||
906 | _omap_dsi_set_irqs_cio(); | ||
907 | |||
908 | spin_unlock_irqrestore(&dsi.irq_lock, flags); | ||
909 | |||
910 | return r; | ||
633 | } | 911 | } |
634 | 912 | ||
635 | static u32 dsi_get_errors(void) | 913 | static u32 dsi_get_errors(void) |
@@ -3383,6 +3661,7 @@ static int dsi_init(struct platform_device *pdev) | |||
3383 | int r, i; | 3661 | int r, i; |
3384 | struct resource *dsi_mem; | 3662 | struct resource *dsi_mem; |
3385 | 3663 | ||
3664 | spin_lock_init(&dsi.irq_lock); | ||
3386 | spin_lock_init(&dsi.errors_lock); | 3665 | spin_lock_init(&dsi.errors_lock); |
3387 | dsi.errors = 0; | 3666 | dsi.errors = 0; |
3388 | 3667 | ||