diff options
Diffstat (limited to 'drivers/video/omap2/dss')
24 files changed, 4129 insertions, 2233 deletions
diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig index b337a8469fd8..80f5390aa136 100644 --- a/drivers/video/omap2/dss/Kconfig +++ b/drivers/video/omap2/dss/Kconfig | |||
@@ -84,7 +84,7 @@ config OMAP2_DSS_SDI | |||
84 | 84 | ||
85 | config OMAP2_DSS_DSI | 85 | config OMAP2_DSS_DSI |
86 | bool "DSI support" | 86 | bool "DSI support" |
87 | depends on ARCH_OMAP3 || ARCH_OMAP4 | 87 | depends on ARCH_OMAP3 || ARCH_OMAP4 || ARCH_OMAP5 |
88 | default n | 88 | default n |
89 | help | 89 | help |
90 | MIPI DSI (Display Serial Interface) support. | 90 | MIPI DSI (Display Serial Interface) support. |
diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile index 5c450b0f94d0..4549869bfe1a 100644 --- a/drivers/video/omap2/dss/Makefile +++ b/drivers/video/omap2/dss/Makefile | |||
@@ -1,9 +1,9 @@ | |||
1 | obj-$(CONFIG_OMAP2_DSS) += omapdss.o | 1 | obj-$(CONFIG_OMAP2_DSS) += omapdss.o |
2 | omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \ | 2 | omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \ |
3 | manager.o overlay.o apply.o | 3 | manager.o manager-sysfs.o overlay.o overlay-sysfs.o output.o apply.o |
4 | omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o | 4 | omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o |
5 | omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o | 5 | omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o |
6 | omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o | 6 | omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o venc_panel.o |
7 | omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o | 7 | omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o |
8 | omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o | 8 | omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o |
9 | omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi.o \ | 9 | omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi.o \ |
diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c index 0fefc68372b9..19d66f471b4b 100644 --- a/drivers/video/omap2/dss/apply.c +++ b/drivers/video/omap2/dss/apply.c | |||
@@ -111,9 +111,6 @@ static struct { | |||
111 | struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS]; | 111 | struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS]; |
112 | struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS]; | 112 | struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS]; |
113 | 113 | ||
114 | bool fifo_merge_dirty; | ||
115 | bool fifo_merge; | ||
116 | |||
117 | bool irq_enabled; | 114 | bool irq_enabled; |
118 | } dss_data; | 115 | } dss_data; |
119 | 116 | ||
@@ -424,17 +421,25 @@ static void wait_pending_extra_info_updates(void) | |||
424 | int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) | 421 | int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) |
425 | { | 422 | { |
426 | unsigned long timeout = msecs_to_jiffies(500); | 423 | unsigned long timeout = msecs_to_jiffies(500); |
427 | struct mgr_priv_data *mp; | 424 | struct mgr_priv_data *mp = get_mgr_priv(mgr); |
428 | u32 irq; | 425 | u32 irq; |
426 | unsigned long flags; | ||
429 | int r; | 427 | int r; |
430 | int i; | 428 | int i; |
431 | struct omap_dss_device *dssdev = mgr->device; | ||
432 | 429 | ||
433 | if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | 430 | spin_lock_irqsave(&data_lock, flags); |
431 | |||
432 | if (mgr_manual_update(mgr)) { | ||
433 | spin_unlock_irqrestore(&data_lock, flags); | ||
434 | return 0; | 434 | return 0; |
435 | } | ||
435 | 436 | ||
436 | if (mgr_manual_update(mgr)) | 437 | if (!mp->enabled) { |
438 | spin_unlock_irqrestore(&data_lock, flags); | ||
437 | return 0; | 439 | return 0; |
440 | } | ||
441 | |||
442 | spin_unlock_irqrestore(&data_lock, flags); | ||
438 | 443 | ||
439 | r = dispc_runtime_get(); | 444 | r = dispc_runtime_get(); |
440 | if (r) | 445 | if (r) |
@@ -442,10 +447,8 @@ int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) | |||
442 | 447 | ||
443 | irq = dispc_mgr_get_vsync_irq(mgr->id); | 448 | irq = dispc_mgr_get_vsync_irq(mgr->id); |
444 | 449 | ||
445 | mp = get_mgr_priv(mgr); | ||
446 | i = 0; | 450 | i = 0; |
447 | while (1) { | 451 | while (1) { |
448 | unsigned long flags; | ||
449 | bool shadow_dirty, dirty; | 452 | bool shadow_dirty, dirty; |
450 | 453 | ||
451 | spin_lock_irqsave(&data_lock, flags); | 454 | spin_lock_irqsave(&data_lock, flags); |
@@ -489,21 +492,30 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) | |||
489 | { | 492 | { |
490 | unsigned long timeout = msecs_to_jiffies(500); | 493 | unsigned long timeout = msecs_to_jiffies(500); |
491 | struct ovl_priv_data *op; | 494 | struct ovl_priv_data *op; |
492 | struct omap_dss_device *dssdev; | 495 | struct mgr_priv_data *mp; |
493 | u32 irq; | 496 | u32 irq; |
497 | unsigned long flags; | ||
494 | int r; | 498 | int r; |
495 | int i; | 499 | int i; |
496 | 500 | ||
497 | if (!ovl->manager) | 501 | if (!ovl->manager) |
498 | return 0; | 502 | return 0; |
499 | 503 | ||
500 | dssdev = ovl->manager->device; | 504 | mp = get_mgr_priv(ovl->manager); |
505 | |||
506 | spin_lock_irqsave(&data_lock, flags); | ||
501 | 507 | ||
502 | if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | 508 | if (ovl_manual_update(ovl)) { |
509 | spin_unlock_irqrestore(&data_lock, flags); | ||
503 | return 0; | 510 | return 0; |
511 | } | ||
504 | 512 | ||
505 | if (ovl_manual_update(ovl)) | 513 | if (!mp->enabled) { |
514 | spin_unlock_irqrestore(&data_lock, flags); | ||
506 | return 0; | 515 | return 0; |
516 | } | ||
517 | |||
518 | spin_unlock_irqrestore(&data_lock, flags); | ||
507 | 519 | ||
508 | r = dispc_runtime_get(); | 520 | r = dispc_runtime_get(); |
509 | if (r) | 521 | if (r) |
@@ -514,7 +526,6 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) | |||
514 | op = get_ovl_priv(ovl); | 526 | op = get_ovl_priv(ovl); |
515 | i = 0; | 527 | i = 0; |
516 | while (1) { | 528 | while (1) { |
517 | unsigned long flags; | ||
518 | bool shadow_dirty, dirty; | 529 | bool shadow_dirty, dirty; |
519 | 530 | ||
520 | spin_lock_irqsave(&data_lock, flags); | 531 | spin_lock_irqsave(&data_lock, flags); |
@@ -573,7 +584,7 @@ static void dss_ovl_write_regs(struct omap_overlay *ovl) | |||
573 | 584 | ||
574 | replication = dss_ovl_use_replication(mp->lcd_config, oi->color_mode); | 585 | replication = dss_ovl_use_replication(mp->lcd_config, oi->color_mode); |
575 | 586 | ||
576 | r = dispc_ovl_setup(ovl->id, oi, replication, &mp->timings); | 587 | r = dispc_ovl_setup(ovl->id, oi, replication, &mp->timings, false); |
577 | if (r) { | 588 | if (r) { |
578 | /* | 589 | /* |
579 | * We can't do much here, as this function can be called from | 590 | * We can't do much here, as this function can be called from |
@@ -677,40 +688,11 @@ static void dss_mgr_write_regs_extra(struct omap_overlay_manager *mgr) | |||
677 | mp->shadow_extra_info_dirty = true; | 688 | mp->shadow_extra_info_dirty = true; |
678 | } | 689 | } |
679 | 690 | ||
680 | static void dss_write_regs_common(void) | ||
681 | { | ||
682 | const int num_mgrs = omap_dss_get_num_overlay_managers(); | ||
683 | int i; | ||
684 | |||
685 | if (!dss_data.fifo_merge_dirty) | ||
686 | return; | ||
687 | |||
688 | for (i = 0; i < num_mgrs; ++i) { | ||
689 | struct omap_overlay_manager *mgr; | ||
690 | struct mgr_priv_data *mp; | ||
691 | |||
692 | mgr = omap_dss_get_overlay_manager(i); | ||
693 | mp = get_mgr_priv(mgr); | ||
694 | |||
695 | if (mp->enabled) { | ||
696 | if (dss_data.fifo_merge_dirty) { | ||
697 | dispc_enable_fifomerge(dss_data.fifo_merge); | ||
698 | dss_data.fifo_merge_dirty = false; | ||
699 | } | ||
700 | |||
701 | if (mp->updating) | ||
702 | mp->shadow_info_dirty = true; | ||
703 | } | ||
704 | } | ||
705 | } | ||
706 | |||
707 | static void dss_write_regs(void) | 691 | static void dss_write_regs(void) |
708 | { | 692 | { |
709 | const int num_mgrs = omap_dss_get_num_overlay_managers(); | 693 | const int num_mgrs = omap_dss_get_num_overlay_managers(); |
710 | int i; | 694 | int i; |
711 | 695 | ||
712 | dss_write_regs_common(); | ||
713 | |||
714 | for (i = 0; i < num_mgrs; ++i) { | 696 | for (i = 0; i < num_mgrs; ++i) { |
715 | struct omap_overlay_manager *mgr; | 697 | struct omap_overlay_manager *mgr; |
716 | struct mgr_priv_data *mp; | 698 | struct mgr_priv_data *mp; |
@@ -799,8 +781,6 @@ void dss_mgr_start_update(struct omap_overlay_manager *mgr) | |||
799 | dss_mgr_write_regs(mgr); | 781 | dss_mgr_write_regs(mgr); |
800 | dss_mgr_write_regs_extra(mgr); | 782 | dss_mgr_write_regs_extra(mgr); |
801 | 783 | ||
802 | dss_write_regs_common(); | ||
803 | |||
804 | mp->updating = true; | 784 | mp->updating = true; |
805 | 785 | ||
806 | if (!dss_data.irq_enabled && need_isr()) | 786 | if (!dss_data.irq_enabled && need_isr()) |
@@ -984,20 +964,11 @@ static void dss_apply_ovl_fifo_thresholds(struct omap_overlay *ovl, | |||
984 | op->extra_info_dirty = true; | 964 | op->extra_info_dirty = true; |
985 | } | 965 | } |
986 | 966 | ||
987 | static void dss_apply_fifo_merge(bool use_fifo_merge) | 967 | static void dss_ovl_setup_fifo(struct omap_overlay *ovl) |
988 | { | ||
989 | if (dss_data.fifo_merge == use_fifo_merge) | ||
990 | return; | ||
991 | |||
992 | dss_data.fifo_merge = use_fifo_merge; | ||
993 | dss_data.fifo_merge_dirty = true; | ||
994 | } | ||
995 | |||
996 | static void dss_ovl_setup_fifo(struct omap_overlay *ovl, | ||
997 | bool use_fifo_merge) | ||
998 | { | 968 | { |
999 | struct ovl_priv_data *op = get_ovl_priv(ovl); | 969 | struct ovl_priv_data *op = get_ovl_priv(ovl); |
1000 | u32 fifo_low, fifo_high; | 970 | u32 fifo_low, fifo_high; |
971 | bool use_fifo_merge = false; | ||
1001 | 972 | ||
1002 | if (!op->enabled && !op->enabling) | 973 | if (!op->enabled && !op->enabling) |
1003 | return; | 974 | return; |
@@ -1008,8 +979,7 @@ static void dss_ovl_setup_fifo(struct omap_overlay *ovl, | |||
1008 | dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high); | 979 | dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high); |
1009 | } | 980 | } |
1010 | 981 | ||
1011 | static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr, | 982 | static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr) |
1012 | bool use_fifo_merge) | ||
1013 | { | 983 | { |
1014 | struct omap_overlay *ovl; | 984 | struct omap_overlay *ovl; |
1015 | struct mgr_priv_data *mp; | 985 | struct mgr_priv_data *mp; |
@@ -1020,94 +990,19 @@ static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr, | |||
1020 | return; | 990 | return; |
1021 | 991 | ||
1022 | list_for_each_entry(ovl, &mgr->overlays, list) | 992 | list_for_each_entry(ovl, &mgr->overlays, list) |
1023 | dss_ovl_setup_fifo(ovl, use_fifo_merge); | 993 | dss_ovl_setup_fifo(ovl); |
1024 | } | ||
1025 | |||
1026 | static void dss_setup_fifos(bool use_fifo_merge) | ||
1027 | { | ||
1028 | const int num_mgrs = omap_dss_get_num_overlay_managers(); | ||
1029 | struct omap_overlay_manager *mgr; | ||
1030 | int i; | ||
1031 | |||
1032 | for (i = 0; i < num_mgrs; ++i) { | ||
1033 | mgr = omap_dss_get_overlay_manager(i); | ||
1034 | dss_mgr_setup_fifos(mgr, use_fifo_merge); | ||
1035 | } | ||
1036 | } | 994 | } |
1037 | 995 | ||
1038 | static int get_num_used_managers(void) | 996 | static void dss_setup_fifos(void) |
1039 | { | 997 | { |
1040 | const int num_mgrs = omap_dss_get_num_overlay_managers(); | 998 | const int num_mgrs = omap_dss_get_num_overlay_managers(); |
1041 | struct omap_overlay_manager *mgr; | 999 | struct omap_overlay_manager *mgr; |
1042 | struct mgr_priv_data *mp; | ||
1043 | int i; | 1000 | int i; |
1044 | int enabled_mgrs; | ||
1045 | |||
1046 | enabled_mgrs = 0; | ||
1047 | 1001 | ||
1048 | for (i = 0; i < num_mgrs; ++i) { | 1002 | for (i = 0; i < num_mgrs; ++i) { |
1049 | mgr = omap_dss_get_overlay_manager(i); | 1003 | mgr = omap_dss_get_overlay_manager(i); |
1050 | mp = get_mgr_priv(mgr); | 1004 | dss_mgr_setup_fifos(mgr); |
1051 | |||
1052 | if (!mp->enabled) | ||
1053 | continue; | ||
1054 | |||
1055 | enabled_mgrs++; | ||
1056 | } | 1005 | } |
1057 | |||
1058 | return enabled_mgrs; | ||
1059 | } | ||
1060 | |||
1061 | static int get_num_used_overlays(void) | ||
1062 | { | ||
1063 | const int num_ovls = omap_dss_get_num_overlays(); | ||
1064 | struct omap_overlay *ovl; | ||
1065 | struct ovl_priv_data *op; | ||
1066 | struct mgr_priv_data *mp; | ||
1067 | int i; | ||
1068 | int enabled_ovls; | ||
1069 | |||
1070 | enabled_ovls = 0; | ||
1071 | |||
1072 | for (i = 0; i < num_ovls; ++i) { | ||
1073 | ovl = omap_dss_get_overlay(i); | ||
1074 | op = get_ovl_priv(ovl); | ||
1075 | |||
1076 | if (!op->enabled && !op->enabling) | ||
1077 | continue; | ||
1078 | |||
1079 | mp = get_mgr_priv(ovl->manager); | ||
1080 | |||
1081 | if (!mp->enabled) | ||
1082 | continue; | ||
1083 | |||
1084 | enabled_ovls++; | ||
1085 | } | ||
1086 | |||
1087 | return enabled_ovls; | ||
1088 | } | ||
1089 | |||
1090 | static bool get_use_fifo_merge(void) | ||
1091 | { | ||
1092 | int enabled_mgrs = get_num_used_managers(); | ||
1093 | int enabled_ovls = get_num_used_overlays(); | ||
1094 | |||
1095 | if (!dss_has_feature(FEAT_FIFO_MERGE)) | ||
1096 | return false; | ||
1097 | |||
1098 | /* | ||
1099 | * In theory the only requirement for fifomerge is enabled_ovls <= 1. | ||
1100 | * However, if we have two managers enabled and set/unset the fifomerge, | ||
1101 | * we need to set the GO bits in particular sequence for the managers, | ||
1102 | * and wait in between. | ||
1103 | * | ||
1104 | * This is rather difficult as new apply calls can happen at any time, | ||
1105 | * so we simplify the problem by requiring also that enabled_mgrs <= 1. | ||
1106 | * In practice this shouldn't matter, because when only one overlay is | ||
1107 | * enabled, most likely only one output is enabled. | ||
1108 | */ | ||
1109 | |||
1110 | return enabled_mgrs <= 1 && enabled_ovls <= 1; | ||
1111 | } | 1006 | } |
1112 | 1007 | ||
1113 | int dss_mgr_enable(struct omap_overlay_manager *mgr) | 1008 | int dss_mgr_enable(struct omap_overlay_manager *mgr) |
@@ -1115,7 +1010,6 @@ int dss_mgr_enable(struct omap_overlay_manager *mgr) | |||
1115 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | 1010 | struct mgr_priv_data *mp = get_mgr_priv(mgr); |
1116 | unsigned long flags; | 1011 | unsigned long flags; |
1117 | int r; | 1012 | int r; |
1118 | bool fifo_merge; | ||
1119 | 1013 | ||
1120 | mutex_lock(&apply_lock); | 1014 | mutex_lock(&apply_lock); |
1121 | 1015 | ||
@@ -1133,23 +1027,11 @@ int dss_mgr_enable(struct omap_overlay_manager *mgr) | |||
1133 | goto err; | 1027 | goto err; |
1134 | } | 1028 | } |
1135 | 1029 | ||
1136 | /* step 1: setup fifos/fifomerge before enabling the manager */ | 1030 | dss_setup_fifos(); |
1137 | |||
1138 | fifo_merge = get_use_fifo_merge(); | ||
1139 | dss_setup_fifos(fifo_merge); | ||
1140 | dss_apply_fifo_merge(fifo_merge); | ||
1141 | 1031 | ||
1142 | dss_write_regs(); | 1032 | dss_write_regs(); |
1143 | dss_set_go_bits(); | 1033 | dss_set_go_bits(); |
1144 | 1034 | ||
1145 | spin_unlock_irqrestore(&data_lock, flags); | ||
1146 | |||
1147 | /* wait until fifo config is in */ | ||
1148 | wait_pending_extra_info_updates(); | ||
1149 | |||
1150 | /* step 2: enable the manager */ | ||
1151 | spin_lock_irqsave(&data_lock, flags); | ||
1152 | |||
1153 | if (!mgr_manual_update(mgr)) | 1035 | if (!mgr_manual_update(mgr)) |
1154 | mp->updating = true; | 1036 | mp->updating = true; |
1155 | 1037 | ||
@@ -1174,7 +1056,6 @@ void dss_mgr_disable(struct omap_overlay_manager *mgr) | |||
1174 | { | 1056 | { |
1175 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | 1057 | struct mgr_priv_data *mp = get_mgr_priv(mgr); |
1176 | unsigned long flags; | 1058 | unsigned long flags; |
1177 | bool fifo_merge; | ||
1178 | 1059 | ||
1179 | mutex_lock(&apply_lock); | 1060 | mutex_lock(&apply_lock); |
1180 | 1061 | ||
@@ -1189,16 +1070,8 @@ void dss_mgr_disable(struct omap_overlay_manager *mgr) | |||
1189 | mp->updating = false; | 1070 | mp->updating = false; |
1190 | mp->enabled = false; | 1071 | mp->enabled = false; |
1191 | 1072 | ||
1192 | fifo_merge = get_use_fifo_merge(); | ||
1193 | dss_setup_fifos(fifo_merge); | ||
1194 | dss_apply_fifo_merge(fifo_merge); | ||
1195 | |||
1196 | dss_write_regs(); | ||
1197 | dss_set_go_bits(); | ||
1198 | |||
1199 | spin_unlock_irqrestore(&data_lock, flags); | 1073 | spin_unlock_irqrestore(&data_lock, flags); |
1200 | 1074 | ||
1201 | wait_pending_extra_info_updates(); | ||
1202 | out: | 1075 | out: |
1203 | mutex_unlock(&apply_lock); | 1076 | mutex_unlock(&apply_lock); |
1204 | } | 1077 | } |
@@ -1237,29 +1110,29 @@ void dss_mgr_get_info(struct omap_overlay_manager *mgr, | |||
1237 | spin_unlock_irqrestore(&data_lock, flags); | 1110 | spin_unlock_irqrestore(&data_lock, flags); |
1238 | } | 1111 | } |
1239 | 1112 | ||
1240 | int dss_mgr_set_device(struct omap_overlay_manager *mgr, | 1113 | int dss_mgr_set_output(struct omap_overlay_manager *mgr, |
1241 | struct omap_dss_device *dssdev) | 1114 | struct omap_dss_output *output) |
1242 | { | 1115 | { |
1243 | int r; | 1116 | int r; |
1244 | 1117 | ||
1245 | mutex_lock(&apply_lock); | 1118 | mutex_lock(&apply_lock); |
1246 | 1119 | ||
1247 | if (dssdev->manager) { | 1120 | if (mgr->output) { |
1248 | DSSERR("display '%s' already has a manager '%s'\n", | 1121 | DSSERR("manager %s is already connected to an output\n", |
1249 | dssdev->name, dssdev->manager->name); | 1122 | mgr->name); |
1250 | r = -EINVAL; | 1123 | r = -EINVAL; |
1251 | goto err; | 1124 | goto err; |
1252 | } | 1125 | } |
1253 | 1126 | ||
1254 | if ((mgr->supported_displays & dssdev->type) == 0) { | 1127 | if ((mgr->supported_outputs & output->id) == 0) { |
1255 | DSSERR("display '%s' does not support manager '%s'\n", | 1128 | DSSERR("output does not support manager %s\n", |
1256 | dssdev->name, mgr->name); | 1129 | mgr->name); |
1257 | r = -EINVAL; | 1130 | r = -EINVAL; |
1258 | goto err; | 1131 | goto err; |
1259 | } | 1132 | } |
1260 | 1133 | ||
1261 | dssdev->manager = mgr; | 1134 | output->manager = mgr; |
1262 | mgr->device = dssdev; | 1135 | mgr->output = output; |
1263 | 1136 | ||
1264 | mutex_unlock(&apply_lock); | 1137 | mutex_unlock(&apply_lock); |
1265 | 1138 | ||
@@ -1269,40 +1142,46 @@ err: | |||
1269 | return r; | 1142 | return r; |
1270 | } | 1143 | } |
1271 | 1144 | ||
1272 | int dss_mgr_unset_device(struct omap_overlay_manager *mgr) | 1145 | int dss_mgr_unset_output(struct omap_overlay_manager *mgr) |
1273 | { | 1146 | { |
1274 | int r; | 1147 | int r; |
1148 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | ||
1149 | unsigned long flags; | ||
1275 | 1150 | ||
1276 | mutex_lock(&apply_lock); | 1151 | mutex_lock(&apply_lock); |
1277 | 1152 | ||
1278 | if (!mgr->device) { | 1153 | if (!mgr->output) { |
1279 | DSSERR("failed to unset display, display not set.\n"); | 1154 | DSSERR("failed to unset output, output not set\n"); |
1280 | r = -EINVAL; | 1155 | r = -EINVAL; |
1281 | goto err; | 1156 | goto err; |
1282 | } | 1157 | } |
1283 | 1158 | ||
1284 | /* | 1159 | spin_lock_irqsave(&data_lock, flags); |
1285 | * Don't allow currently enabled displays to have the overlay manager | 1160 | |
1286 | * pulled out from underneath them | 1161 | if (mp->enabled) { |
1287 | */ | 1162 | DSSERR("output can't be unset when manager is enabled\n"); |
1288 | if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED) { | ||
1289 | r = -EINVAL; | 1163 | r = -EINVAL; |
1290 | goto err; | 1164 | goto err1; |
1291 | } | 1165 | } |
1292 | 1166 | ||
1293 | mgr->device->manager = NULL; | 1167 | spin_unlock_irqrestore(&data_lock, flags); |
1294 | mgr->device = NULL; | 1168 | |
1169 | mgr->output->manager = NULL; | ||
1170 | mgr->output = NULL; | ||
1295 | 1171 | ||
1296 | mutex_unlock(&apply_lock); | 1172 | mutex_unlock(&apply_lock); |
1297 | 1173 | ||
1298 | return 0; | 1174 | return 0; |
1175 | err1: | ||
1176 | spin_unlock_irqrestore(&data_lock, flags); | ||
1299 | err: | 1177 | err: |
1300 | mutex_unlock(&apply_lock); | 1178 | mutex_unlock(&apply_lock); |
1179 | |||
1301 | return r; | 1180 | return r; |
1302 | } | 1181 | } |
1303 | 1182 | ||
1304 | static void dss_apply_mgr_timings(struct omap_overlay_manager *mgr, | 1183 | static void dss_apply_mgr_timings(struct omap_overlay_manager *mgr, |
1305 | struct omap_video_timings *timings) | 1184 | const struct omap_video_timings *timings) |
1306 | { | 1185 | { |
1307 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | 1186 | struct mgr_priv_data *mp = get_mgr_priv(mgr); |
1308 | 1187 | ||
@@ -1311,24 +1190,22 @@ static void dss_apply_mgr_timings(struct omap_overlay_manager *mgr, | |||
1311 | } | 1190 | } |
1312 | 1191 | ||
1313 | void dss_mgr_set_timings(struct omap_overlay_manager *mgr, | 1192 | void dss_mgr_set_timings(struct omap_overlay_manager *mgr, |
1314 | struct omap_video_timings *timings) | 1193 | const struct omap_video_timings *timings) |
1315 | { | 1194 | { |
1316 | unsigned long flags; | 1195 | unsigned long flags; |
1317 | 1196 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | |
1318 | mutex_lock(&apply_lock); | ||
1319 | 1197 | ||
1320 | spin_lock_irqsave(&data_lock, flags); | 1198 | spin_lock_irqsave(&data_lock, flags); |
1321 | 1199 | ||
1322 | dss_apply_mgr_timings(mgr, timings); | 1200 | if (mp->updating) { |
1323 | 1201 | DSSERR("cannot set timings for %s: manager needs to be disabled\n", | |
1324 | dss_write_regs(); | 1202 | mgr->name); |
1325 | dss_set_go_bits(); | 1203 | goto out; |
1204 | } | ||
1326 | 1205 | ||
1206 | dss_apply_mgr_timings(mgr, timings); | ||
1207 | out: | ||
1327 | spin_unlock_irqrestore(&data_lock, flags); | 1208 | spin_unlock_irqrestore(&data_lock, flags); |
1328 | |||
1329 | wait_pending_extra_info_updates(); | ||
1330 | |||
1331 | mutex_unlock(&apply_lock); | ||
1332 | } | 1209 | } |
1333 | 1210 | ||
1334 | static void dss_apply_mgr_lcd_config(struct omap_overlay_manager *mgr, | 1211 | static void dss_apply_mgr_lcd_config(struct omap_overlay_manager *mgr, |
@@ -1346,7 +1223,7 @@ void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr, | |||
1346 | unsigned long flags; | 1223 | unsigned long flags; |
1347 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | 1224 | struct mgr_priv_data *mp = get_mgr_priv(mgr); |
1348 | 1225 | ||
1349 | mutex_lock(&apply_lock); | 1226 | spin_lock_irqsave(&data_lock, flags); |
1350 | 1227 | ||
1351 | if (mp->enabled) { | 1228 | if (mp->enabled) { |
1352 | DSSERR("cannot apply lcd config for %s: manager needs to be disabled\n", | 1229 | DSSERR("cannot apply lcd config for %s: manager needs to be disabled\n", |
@@ -1354,19 +1231,9 @@ void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr, | |||
1354 | goto out; | 1231 | goto out; |
1355 | } | 1232 | } |
1356 | 1233 | ||
1357 | spin_lock_irqsave(&data_lock, flags); | ||
1358 | |||
1359 | dss_apply_mgr_lcd_config(mgr, config); | 1234 | dss_apply_mgr_lcd_config(mgr, config); |
1360 | |||
1361 | dss_write_regs(); | ||
1362 | dss_set_go_bits(); | ||
1363 | |||
1364 | spin_unlock_irqrestore(&data_lock, flags); | ||
1365 | |||
1366 | wait_pending_extra_info_updates(); | ||
1367 | |||
1368 | out: | 1235 | out: |
1369 | mutex_unlock(&apply_lock); | 1236 | spin_unlock_irqrestore(&data_lock, flags); |
1370 | } | 1237 | } |
1371 | 1238 | ||
1372 | int dss_ovl_set_info(struct omap_overlay *ovl, | 1239 | int dss_ovl_set_info(struct omap_overlay *ovl, |
@@ -1483,6 +1350,13 @@ int dss_ovl_unset_manager(struct omap_overlay *ovl) | |||
1483 | goto err; | 1350 | goto err; |
1484 | } | 1351 | } |
1485 | 1352 | ||
1353 | spin_unlock_irqrestore(&data_lock, flags); | ||
1354 | |||
1355 | /* wait for pending extra_info updates to ensure the ovl is disabled */ | ||
1356 | wait_pending_extra_info_updates(); | ||
1357 | |||
1358 | spin_lock_irqsave(&data_lock, flags); | ||
1359 | |||
1486 | op->channel = -1; | 1360 | op->channel = -1; |
1487 | 1361 | ||
1488 | ovl->manager = NULL; | 1362 | ovl->manager = NULL; |
@@ -1517,7 +1391,6 @@ int dss_ovl_enable(struct omap_overlay *ovl) | |||
1517 | { | 1391 | { |
1518 | struct ovl_priv_data *op = get_ovl_priv(ovl); | 1392 | struct ovl_priv_data *op = get_ovl_priv(ovl); |
1519 | unsigned long flags; | 1393 | unsigned long flags; |
1520 | bool fifo_merge; | ||
1521 | int r; | 1394 | int r; |
1522 | 1395 | ||
1523 | mutex_lock(&apply_lock); | 1396 | mutex_lock(&apply_lock); |
@@ -1527,7 +1400,7 @@ int dss_ovl_enable(struct omap_overlay *ovl) | |||
1527 | goto err1; | 1400 | goto err1; |
1528 | } | 1401 | } |
1529 | 1402 | ||
1530 | if (ovl->manager == NULL || ovl->manager->device == NULL) { | 1403 | if (ovl->manager == NULL || ovl->manager->output == NULL) { |
1531 | r = -EINVAL; | 1404 | r = -EINVAL; |
1532 | goto err1; | 1405 | goto err1; |
1533 | } | 1406 | } |
@@ -1543,22 +1416,7 @@ int dss_ovl_enable(struct omap_overlay *ovl) | |||
1543 | goto err2; | 1416 | goto err2; |
1544 | } | 1417 | } |
1545 | 1418 | ||
1546 | /* step 1: configure fifos/fifomerge for currently enabled ovls */ | 1419 | dss_setup_fifos(); |
1547 | |||
1548 | fifo_merge = get_use_fifo_merge(); | ||
1549 | dss_setup_fifos(fifo_merge); | ||
1550 | dss_apply_fifo_merge(fifo_merge); | ||
1551 | |||
1552 | dss_write_regs(); | ||
1553 | dss_set_go_bits(); | ||
1554 | |||
1555 | spin_unlock_irqrestore(&data_lock, flags); | ||
1556 | |||
1557 | /* wait for fifo configs to go in */ | ||
1558 | wait_pending_extra_info_updates(); | ||
1559 | |||
1560 | /* step 2: enable the overlay */ | ||
1561 | spin_lock_irqsave(&data_lock, flags); | ||
1562 | 1420 | ||
1563 | op->enabling = false; | 1421 | op->enabling = false; |
1564 | dss_apply_ovl_enable(ovl, true); | 1422 | dss_apply_ovl_enable(ovl, true); |
@@ -1568,9 +1426,6 @@ int dss_ovl_enable(struct omap_overlay *ovl) | |||
1568 | 1426 | ||
1569 | spin_unlock_irqrestore(&data_lock, flags); | 1427 | spin_unlock_irqrestore(&data_lock, flags); |
1570 | 1428 | ||
1571 | /* wait for overlay to be enabled */ | ||
1572 | wait_pending_extra_info_updates(); | ||
1573 | |||
1574 | mutex_unlock(&apply_lock); | 1429 | mutex_unlock(&apply_lock); |
1575 | 1430 | ||
1576 | return 0; | 1431 | return 0; |
@@ -1586,7 +1441,6 @@ int dss_ovl_disable(struct omap_overlay *ovl) | |||
1586 | { | 1441 | { |
1587 | struct ovl_priv_data *op = get_ovl_priv(ovl); | 1442 | struct ovl_priv_data *op = get_ovl_priv(ovl); |
1588 | unsigned long flags; | 1443 | unsigned long flags; |
1589 | bool fifo_merge; | ||
1590 | int r; | 1444 | int r; |
1591 | 1445 | ||
1592 | mutex_lock(&apply_lock); | 1446 | mutex_lock(&apply_lock); |
@@ -1596,39 +1450,19 @@ int dss_ovl_disable(struct omap_overlay *ovl) | |||
1596 | goto err; | 1450 | goto err; |
1597 | } | 1451 | } |
1598 | 1452 | ||
1599 | if (ovl->manager == NULL || ovl->manager->device == NULL) { | 1453 | if (ovl->manager == NULL || ovl->manager->output == NULL) { |
1600 | r = -EINVAL; | 1454 | r = -EINVAL; |
1601 | goto err; | 1455 | goto err; |
1602 | } | 1456 | } |
1603 | 1457 | ||
1604 | /* step 1: disable the overlay */ | ||
1605 | spin_lock_irqsave(&data_lock, flags); | 1458 | spin_lock_irqsave(&data_lock, flags); |
1606 | 1459 | ||
1607 | dss_apply_ovl_enable(ovl, false); | 1460 | dss_apply_ovl_enable(ovl, false); |
1608 | |||
1609 | dss_write_regs(); | 1461 | dss_write_regs(); |
1610 | dss_set_go_bits(); | 1462 | dss_set_go_bits(); |
1611 | 1463 | ||
1612 | spin_unlock_irqrestore(&data_lock, flags); | 1464 | spin_unlock_irqrestore(&data_lock, flags); |
1613 | 1465 | ||
1614 | /* wait for the overlay to be disabled */ | ||
1615 | wait_pending_extra_info_updates(); | ||
1616 | |||
1617 | /* step 2: configure fifos/fifomerge */ | ||
1618 | spin_lock_irqsave(&data_lock, flags); | ||
1619 | |||
1620 | fifo_merge = get_use_fifo_merge(); | ||
1621 | dss_setup_fifos(fifo_merge); | ||
1622 | dss_apply_fifo_merge(fifo_merge); | ||
1623 | |||
1624 | dss_write_regs(); | ||
1625 | dss_set_go_bits(); | ||
1626 | |||
1627 | spin_unlock_irqrestore(&data_lock, flags); | ||
1628 | |||
1629 | /* wait for fifo config to go in */ | ||
1630 | wait_pending_extra_info_updates(); | ||
1631 | |||
1632 | mutex_unlock(&apply_lock); | 1466 | mutex_unlock(&apply_lock); |
1633 | 1467 | ||
1634 | return 0; | 1468 | return 0; |
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index 58bd9c27369d..b2af72dc20bd 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/device.h> | 33 | #include <linux/device.h> |
34 | #include <linux/regulator/consumer.h> | 34 | #include <linux/regulator/consumer.h> |
35 | #include <linux/suspend.h> | 35 | #include <linux/suspend.h> |
36 | #include <linux/slab.h> | ||
36 | 37 | ||
37 | #include <video/omapdss.h> | 38 | #include <video/omapdss.h> |
38 | 39 | ||
@@ -57,6 +58,11 @@ bool dss_debug; | |||
57 | module_param_named(debug, dss_debug, bool, 0644); | 58 | module_param_named(debug, dss_debug, bool, 0644); |
58 | #endif | 59 | #endif |
59 | 60 | ||
61 | const char *dss_get_default_display_name(void) | ||
62 | { | ||
63 | return core.default_display_name; | ||
64 | } | ||
65 | |||
60 | /* REGULATORS */ | 66 | /* REGULATORS */ |
61 | 67 | ||
62 | struct regulator *dss_get_vdds_dsi(void) | 68 | struct regulator *dss_get_vdds_dsi(void) |
@@ -347,17 +353,14 @@ static int dss_driver_probe(struct device *dev) | |||
347 | int r; | 353 | int r; |
348 | struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver); | 354 | struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver); |
349 | struct omap_dss_device *dssdev = to_dss_device(dev); | 355 | struct omap_dss_device *dssdev = to_dss_device(dev); |
350 | bool force; | ||
351 | 356 | ||
352 | DSSDBG("driver_probe: dev %s/%s, drv %s\n", | 357 | DSSDBG("driver_probe: dev %s/%s, drv %s\n", |
353 | dev_name(dev), dssdev->driver_name, | 358 | dev_name(dev), dssdev->driver_name, |
354 | dssdrv->driver.name); | 359 | dssdrv->driver.name); |
355 | 360 | ||
356 | dss_init_device(core.pdev, dssdev); | 361 | r = dss_init_device(core.pdev, dssdev); |
357 | 362 | if (r) | |
358 | force = core.default_display_name && | 363 | return r; |
359 | strcmp(core.default_display_name, dssdev->name) == 0; | ||
360 | dss_recheck_connections(dssdev, force); | ||
361 | 364 | ||
362 | r = dssdrv->probe(dssdev); | 365 | r = dssdrv->probe(dssdev); |
363 | 366 | ||
@@ -416,54 +419,44 @@ void omap_dss_unregister_driver(struct omap_dss_driver *dssdriver) | |||
416 | EXPORT_SYMBOL(omap_dss_unregister_driver); | 419 | EXPORT_SYMBOL(omap_dss_unregister_driver); |
417 | 420 | ||
418 | /* DEVICE */ | 421 | /* DEVICE */ |
419 | static void reset_device(struct device *dev, int check) | ||
420 | { | ||
421 | u8 *dev_p = (u8 *)dev; | ||
422 | u8 *dev_end = dev_p + sizeof(*dev); | ||
423 | void *saved_pdata; | ||
424 | |||
425 | saved_pdata = dev->platform_data; | ||
426 | if (check) { | ||
427 | /* | ||
428 | * Check if there is any other setting than platform_data | ||
429 | * in struct device; warn that these will be reset by our | ||
430 | * init. | ||
431 | */ | ||
432 | dev->platform_data = NULL; | ||
433 | while (dev_p < dev_end) { | ||
434 | if (*dev_p) { | ||
435 | WARN("%s: struct device fields will be " | ||
436 | "discarded\n", | ||
437 | __func__); | ||
438 | break; | ||
439 | } | ||
440 | dev_p++; | ||
441 | } | ||
442 | } | ||
443 | memset(dev, 0, sizeof(*dev)); | ||
444 | dev->platform_data = saved_pdata; | ||
445 | } | ||
446 | |||
447 | 422 | ||
448 | static void omap_dss_dev_release(struct device *dev) | 423 | static void omap_dss_dev_release(struct device *dev) |
449 | { | 424 | { |
450 | reset_device(dev, 0); | 425 | struct omap_dss_device *dssdev = to_dss_device(dev); |
426 | kfree(dssdev); | ||
451 | } | 427 | } |
452 | 428 | ||
453 | int omap_dss_register_device(struct omap_dss_device *dssdev, | 429 | static int disp_num_counter; |
454 | struct device *parent, int disp_num) | 430 | |
431 | struct omap_dss_device *dss_alloc_and_init_device(struct device *parent) | ||
455 | { | 432 | { |
456 | WARN_ON(!dssdev->driver_name); | 433 | struct omap_dss_device *dssdev; |
434 | |||
435 | dssdev = kzalloc(sizeof(*dssdev), GFP_KERNEL); | ||
436 | if (!dssdev) | ||
437 | return NULL; | ||
457 | 438 | ||
458 | reset_device(&dssdev->dev, 1); | ||
459 | dssdev->dev.bus = &dss_bus_type; | 439 | dssdev->dev.bus = &dss_bus_type; |
460 | dssdev->dev.parent = parent; | 440 | dssdev->dev.parent = parent; |
461 | dssdev->dev.release = omap_dss_dev_release; | 441 | dssdev->dev.release = omap_dss_dev_release; |
462 | dev_set_name(&dssdev->dev, "display%d", disp_num); | 442 | dev_set_name(&dssdev->dev, "display%d", disp_num_counter++); |
463 | return device_register(&dssdev->dev); | 443 | |
444 | device_initialize(&dssdev->dev); | ||
445 | |||
446 | return dssdev; | ||
447 | } | ||
448 | |||
449 | int dss_add_device(struct omap_dss_device *dssdev) | ||
450 | { | ||
451 | return device_add(&dssdev->dev); | ||
452 | } | ||
453 | |||
454 | void dss_put_device(struct omap_dss_device *dssdev) | ||
455 | { | ||
456 | put_device(&dssdev->dev); | ||
464 | } | 457 | } |
465 | 458 | ||
466 | void omap_dss_unregister_device(struct omap_dss_device *dssdev) | 459 | void dss_unregister_device(struct omap_dss_device *dssdev) |
467 | { | 460 | { |
468 | device_unregister(&dssdev->dev); | 461 | device_unregister(&dssdev->dev); |
469 | } | 462 | } |
@@ -471,15 +464,25 @@ void omap_dss_unregister_device(struct omap_dss_device *dssdev) | |||
471 | static int dss_unregister_dss_dev(struct device *dev, void *data) | 464 | static int dss_unregister_dss_dev(struct device *dev, void *data) |
472 | { | 465 | { |
473 | struct omap_dss_device *dssdev = to_dss_device(dev); | 466 | struct omap_dss_device *dssdev = to_dss_device(dev); |
474 | omap_dss_unregister_device(dssdev); | 467 | dss_unregister_device(dssdev); |
475 | return 0; | 468 | return 0; |
476 | } | 469 | } |
477 | 470 | ||
478 | void omap_dss_unregister_child_devices(struct device *parent) | 471 | void dss_unregister_child_devices(struct device *parent) |
479 | { | 472 | { |
480 | device_for_each_child(parent, NULL, dss_unregister_dss_dev); | 473 | device_for_each_child(parent, NULL, dss_unregister_dss_dev); |
481 | } | 474 | } |
482 | 475 | ||
476 | void dss_copy_device_pdata(struct omap_dss_device *dst, | ||
477 | const struct omap_dss_device *src) | ||
478 | { | ||
479 | u8 *d = (u8 *)dst; | ||
480 | u8 *s = (u8 *)src; | ||
481 | size_t dsize = sizeof(struct device); | ||
482 | |||
483 | memcpy(d + dsize, s + dsize, sizeof(struct omap_dss_device) - dsize); | ||
484 | } | ||
485 | |||
483 | /* BUS */ | 486 | /* BUS */ |
484 | static int __init omap_dss_bus_register(void) | 487 | static int __init omap_dss_bus_register(void) |
485 | { | 488 | { |
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index ee9e29639dcc..b43477a5fae8 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c | |||
@@ -38,7 +38,6 @@ | |||
38 | #include <linux/pm_runtime.h> | 38 | #include <linux/pm_runtime.h> |
39 | 39 | ||
40 | #include <plat/cpu.h> | 40 | #include <plat/cpu.h> |
41 | #include <plat/clock.h> | ||
42 | 41 | ||
43 | #include <video/omapdss.h> | 42 | #include <video/omapdss.h> |
44 | 43 | ||
@@ -82,6 +81,30 @@ struct dispc_irq_stats { | |||
82 | unsigned irqs[32]; | 81 | unsigned irqs[32]; |
83 | }; | 82 | }; |
84 | 83 | ||
84 | struct dispc_features { | ||
85 | u8 sw_start; | ||
86 | u8 fp_start; | ||
87 | u8 bp_start; | ||
88 | u16 sw_max; | ||
89 | u16 vp_max; | ||
90 | u16 hp_max; | ||
91 | int (*calc_scaling) (enum omap_plane plane, | ||
92 | const struct omap_video_timings *mgr_timings, | ||
93 | u16 width, u16 height, u16 out_width, u16 out_height, | ||
94 | enum omap_color_mode color_mode, bool *five_taps, | ||
95 | int *x_predecim, int *y_predecim, int *decim_x, int *decim_y, | ||
96 | u16 pos_x, unsigned long *core_clk, bool mem_to_mem); | ||
97 | unsigned long (*calc_core_clk) (enum omap_plane plane, | ||
98 | u16 width, u16 height, u16 out_width, u16 out_height, | ||
99 | bool mem_to_mem); | ||
100 | u8 num_fifos; | ||
101 | |||
102 | /* swap GFX & WB fifos */ | ||
103 | bool gfx_fifo_workaround:1; | ||
104 | }; | ||
105 | |||
106 | #define DISPC_MAX_NR_FIFOS 5 | ||
107 | |||
85 | static struct { | 108 | static struct { |
86 | struct platform_device *pdev; | 109 | struct platform_device *pdev; |
87 | void __iomem *base; | 110 | void __iomem *base; |
@@ -91,7 +114,9 @@ static struct { | |||
91 | int irq; | 114 | int irq; |
92 | struct clk *dss_clk; | 115 | struct clk *dss_clk; |
93 | 116 | ||
94 | u32 fifo_size[MAX_DSS_OVERLAYS]; | 117 | u32 fifo_size[DISPC_MAX_NR_FIFOS]; |
118 | /* maps which plane is using a fifo. fifo-id -> plane-id */ | ||
119 | int fifo_assignment[DISPC_MAX_NR_FIFOS]; | ||
95 | 120 | ||
96 | spinlock_t irq_lock; | 121 | spinlock_t irq_lock; |
97 | u32 irq_error_mask; | 122 | u32 irq_error_mask; |
@@ -102,6 +127,8 @@ static struct { | |||
102 | bool ctx_valid; | 127 | bool ctx_valid; |
103 | u32 ctx[DISPC_SZ_REGS / sizeof(u32)]; | 128 | u32 ctx[DISPC_SZ_REGS / sizeof(u32)]; |
104 | 129 | ||
130 | const struct dispc_features *feat; | ||
131 | |||
105 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS | 132 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS |
106 | spinlock_t irq_stats_lock; | 133 | spinlock_t irq_stats_lock; |
107 | struct dispc_irq_stats irq_stats; | 134 | struct dispc_irq_stats irq_stats; |
@@ -211,7 +238,14 @@ static const struct { | |||
211 | }, | 238 | }, |
212 | }; | 239 | }; |
213 | 240 | ||
241 | struct color_conv_coef { | ||
242 | int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb; | ||
243 | int full_range; | ||
244 | }; | ||
245 | |||
214 | static void _omap_dispc_set_irqs(void); | 246 | static void _omap_dispc_set_irqs(void); |
247 | static unsigned long dispc_plane_pclk_rate(enum omap_plane plane); | ||
248 | static unsigned long dispc_plane_lclk_rate(enum omap_plane plane); | ||
215 | 249 | ||
216 | static inline void dispc_write_reg(const u16 idx, u32 val) | 250 | static inline void dispc_write_reg(const u16 idx, u32 val) |
217 | { | 251 | { |
@@ -509,6 +543,11 @@ u32 dispc_mgr_get_framedone_irq(enum omap_channel channel) | |||
509 | return mgr_desc[channel].framedone_irq; | 543 | return mgr_desc[channel].framedone_irq; |
510 | } | 544 | } |
511 | 545 | ||
546 | u32 dispc_wb_get_framedone_irq(void) | ||
547 | { | ||
548 | return DISPC_IRQ_FRAMEDONEWB; | ||
549 | } | ||
550 | |||
512 | bool dispc_mgr_go_busy(enum omap_channel channel) | 551 | bool dispc_mgr_go_busy(enum omap_channel channel) |
513 | { | 552 | { |
514 | return mgr_fld_read(channel, DISPC_MGR_FLD_GO) == 1; | 553 | return mgr_fld_read(channel, DISPC_MGR_FLD_GO) == 1; |
@@ -536,6 +575,30 @@ void dispc_mgr_go(enum omap_channel channel) | |||
536 | mgr_fld_write(channel, DISPC_MGR_FLD_GO, 1); | 575 | mgr_fld_write(channel, DISPC_MGR_FLD_GO, 1); |
537 | } | 576 | } |
538 | 577 | ||
578 | bool dispc_wb_go_busy(void) | ||
579 | { | ||
580 | return REG_GET(DISPC_CONTROL2, 6, 6) == 1; | ||
581 | } | ||
582 | |||
583 | void dispc_wb_go(void) | ||
584 | { | ||
585 | enum omap_plane plane = OMAP_DSS_WB; | ||
586 | bool enable, go; | ||
587 | |||
588 | enable = REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0) == 1; | ||
589 | |||
590 | if (!enable) | ||
591 | return; | ||
592 | |||
593 | go = REG_GET(DISPC_CONTROL2, 6, 6) == 1; | ||
594 | if (go) { | ||
595 | DSSERR("GO bit not down for WB\n"); | ||
596 | return; | ||
597 | } | ||
598 | |||
599 | REG_FLD_MOD(DISPC_CONTROL2, 1, 6, 6); | ||
600 | } | ||
601 | |||
539 | static void dispc_ovl_write_firh_reg(enum omap_plane plane, int reg, u32 value) | 602 | static void dispc_ovl_write_firh_reg(enum omap_plane plane, int reg, u32 value) |
540 | { | 603 | { |
541 | dispc_write_reg(DISPC_OVL_FIR_COEF_H(plane, reg), value); | 604 | dispc_write_reg(DISPC_OVL_FIR_COEF_H(plane, reg), value); |
@@ -618,41 +681,41 @@ static void dispc_ovl_set_scale_coef(enum omap_plane plane, int fir_hinc, | |||
618 | } | 681 | } |
619 | } | 682 | } |
620 | 683 | ||
621 | static void _dispc_setup_color_conv_coef(void) | ||
622 | { | ||
623 | int i; | ||
624 | const struct color_conv_coef { | ||
625 | int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb; | ||
626 | int full_range; | ||
627 | } ctbl_bt601_5 = { | ||
628 | 298, 409, 0, 298, -208, -100, 298, 0, 517, 0, | ||
629 | }; | ||
630 | |||
631 | const struct color_conv_coef *ct; | ||
632 | 684 | ||
685 | static void dispc_ovl_write_color_conv_coef(enum omap_plane plane, | ||
686 | const struct color_conv_coef *ct) | ||
687 | { | ||
633 | #define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0)) | 688 | #define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0)) |
634 | 689 | ||
635 | ct = &ctbl_bt601_5; | 690 | dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 0), CVAL(ct->rcr, ct->ry)); |
691 | dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 1), CVAL(ct->gy, ct->rcb)); | ||
692 | dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 2), CVAL(ct->gcb, ct->gcr)); | ||
693 | dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 3), CVAL(ct->bcr, ct->by)); | ||
694 | dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 4), CVAL(0, ct->bcb)); | ||
636 | 695 | ||
637 | for (i = 1; i < dss_feat_get_num_ovls(); i++) { | 696 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), ct->full_range, 11, 11); |
638 | dispc_write_reg(DISPC_OVL_CONV_COEF(i, 0), | ||
639 | CVAL(ct->rcr, ct->ry)); | ||
640 | dispc_write_reg(DISPC_OVL_CONV_COEF(i, 1), | ||
641 | CVAL(ct->gy, ct->rcb)); | ||
642 | dispc_write_reg(DISPC_OVL_CONV_COEF(i, 2), | ||
643 | CVAL(ct->gcb, ct->gcr)); | ||
644 | dispc_write_reg(DISPC_OVL_CONV_COEF(i, 3), | ||
645 | CVAL(ct->bcr, ct->by)); | ||
646 | dispc_write_reg(DISPC_OVL_CONV_COEF(i, 4), | ||
647 | CVAL(0, ct->bcb)); | ||
648 | |||
649 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), ct->full_range, | ||
650 | 11, 11); | ||
651 | } | ||
652 | 697 | ||
653 | #undef CVAL | 698 | #undef CVAL |
654 | } | 699 | } |
655 | 700 | ||
701 | static void dispc_setup_color_conv_coef(void) | ||
702 | { | ||
703 | int i; | ||
704 | int num_ovl = dss_feat_get_num_ovls(); | ||
705 | int num_wb = dss_feat_get_num_wbs(); | ||
706 | const struct color_conv_coef ctbl_bt601_5_ovl = { | ||
707 | 298, 409, 0, 298, -208, -100, 298, 0, 517, 0, | ||
708 | }; | ||
709 | const struct color_conv_coef ctbl_bt601_5_wb = { | ||
710 | 66, 112, -38, 129, -94, -74, 25, -18, 112, 0, | ||
711 | }; | ||
712 | |||
713 | for (i = 1; i < num_ovl; i++) | ||
714 | dispc_ovl_write_color_conv_coef(i, &ctbl_bt601_5_ovl); | ||
715 | |||
716 | for (; i < num_wb; i++) | ||
717 | dispc_ovl_write_color_conv_coef(i, &ctbl_bt601_5_wb); | ||
718 | } | ||
656 | 719 | ||
657 | static void dispc_ovl_set_ba0(enum omap_plane plane, u32 paddr) | 720 | static void dispc_ovl_set_ba0(enum omap_plane plane, u32 paddr) |
658 | { | 721 | { |
@@ -674,24 +737,32 @@ static void dispc_ovl_set_ba1_uv(enum omap_plane plane, u32 paddr) | |||
674 | dispc_write_reg(DISPC_OVL_BA1_UV(plane), paddr); | 737 | dispc_write_reg(DISPC_OVL_BA1_UV(plane), paddr); |
675 | } | 738 | } |
676 | 739 | ||
677 | static void dispc_ovl_set_pos(enum omap_plane plane, int x, int y) | 740 | static void dispc_ovl_set_pos(enum omap_plane plane, |
741 | enum omap_overlay_caps caps, int x, int y) | ||
678 | { | 742 | { |
679 | u32 val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0); | 743 | u32 val; |
744 | |||
745 | if ((caps & OMAP_DSS_OVL_CAP_POS) == 0) | ||
746 | return; | ||
747 | |||
748 | val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0); | ||
680 | 749 | ||
681 | dispc_write_reg(DISPC_OVL_POSITION(plane), val); | 750 | dispc_write_reg(DISPC_OVL_POSITION(plane), val); |
682 | } | 751 | } |
683 | 752 | ||
684 | static void dispc_ovl_set_pic_size(enum omap_plane plane, int width, int height) | 753 | static void dispc_ovl_set_input_size(enum omap_plane plane, int width, |
754 | int height) | ||
685 | { | 755 | { |
686 | u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); | 756 | u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); |
687 | 757 | ||
688 | if (plane == OMAP_DSS_GFX) | 758 | if (plane == OMAP_DSS_GFX || plane == OMAP_DSS_WB) |
689 | dispc_write_reg(DISPC_OVL_SIZE(plane), val); | 759 | dispc_write_reg(DISPC_OVL_SIZE(plane), val); |
690 | else | 760 | else |
691 | dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val); | 761 | dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val); |
692 | } | 762 | } |
693 | 763 | ||
694 | static void dispc_ovl_set_vid_size(enum omap_plane plane, int width, int height) | 764 | static void dispc_ovl_set_output_size(enum omap_plane plane, int width, |
765 | int height) | ||
695 | { | 766 | { |
696 | u32 val; | 767 | u32 val; |
697 | 768 | ||
@@ -699,14 +770,16 @@ static void dispc_ovl_set_vid_size(enum omap_plane plane, int width, int height) | |||
699 | 770 | ||
700 | val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); | 771 | val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); |
701 | 772 | ||
702 | dispc_write_reg(DISPC_OVL_SIZE(plane), val); | 773 | if (plane == OMAP_DSS_WB) |
774 | dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val); | ||
775 | else | ||
776 | dispc_write_reg(DISPC_OVL_SIZE(plane), val); | ||
703 | } | 777 | } |
704 | 778 | ||
705 | static void dispc_ovl_set_zorder(enum omap_plane plane, u8 zorder) | 779 | static void dispc_ovl_set_zorder(enum omap_plane plane, |
780 | enum omap_overlay_caps caps, u8 zorder) | ||
706 | { | 781 | { |
707 | struct omap_overlay *ovl = omap_dss_get_overlay(plane); | 782 | if ((caps & OMAP_DSS_OVL_CAP_ZORDER) == 0) |
708 | |||
709 | if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0) | ||
710 | return; | 783 | return; |
711 | 784 | ||
712 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), zorder, 27, 26); | 785 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), zorder, 27, 26); |
@@ -723,23 +796,22 @@ static void dispc_ovl_enable_zorder_planes(void) | |||
723 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), 1, 25, 25); | 796 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), 1, 25, 25); |
724 | } | 797 | } |
725 | 798 | ||
726 | static void dispc_ovl_set_pre_mult_alpha(enum omap_plane plane, bool enable) | 799 | static void dispc_ovl_set_pre_mult_alpha(enum omap_plane plane, |
800 | enum omap_overlay_caps caps, bool enable) | ||
727 | { | 801 | { |
728 | struct omap_overlay *ovl = omap_dss_get_overlay(plane); | 802 | if ((caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0) |
729 | |||
730 | if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0) | ||
731 | return; | 803 | return; |
732 | 804 | ||
733 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 28, 28); | 805 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 28, 28); |
734 | } | 806 | } |
735 | 807 | ||
736 | static void dispc_ovl_setup_global_alpha(enum omap_plane plane, u8 global_alpha) | 808 | static void dispc_ovl_setup_global_alpha(enum omap_plane plane, |
809 | enum omap_overlay_caps caps, u8 global_alpha) | ||
737 | { | 810 | { |
738 | static const unsigned shifts[] = { 0, 8, 16, 24, }; | 811 | static const unsigned shifts[] = { 0, 8, 16, 24, }; |
739 | int shift; | 812 | int shift; |
740 | struct omap_overlay *ovl = omap_dss_get_overlay(plane); | ||
741 | 813 | ||
742 | if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0) | 814 | if ((caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0) |
743 | return; | 815 | return; |
744 | 816 | ||
745 | shift = shifts[plane]; | 817 | shift = shifts[plane]; |
@@ -947,10 +1019,17 @@ static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane plane) | |||
947 | return channel; | 1019 | return channel; |
948 | } | 1020 | } |
949 | 1021 | ||
1022 | void dispc_wb_set_channel_in(enum dss_writeback_channel channel) | ||
1023 | { | ||
1024 | enum omap_plane plane = OMAP_DSS_WB; | ||
1025 | |||
1026 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), channel, 18, 16); | ||
1027 | } | ||
1028 | |||
950 | static void dispc_ovl_set_burst_size(enum omap_plane plane, | 1029 | static void dispc_ovl_set_burst_size(enum omap_plane plane, |
951 | enum omap_burst_size burst_size) | 1030 | enum omap_burst_size burst_size) |
952 | { | 1031 | { |
953 | static const unsigned shifts[] = { 6, 14, 14, 14, }; | 1032 | static const unsigned shifts[] = { 6, 14, 14, 14, 14, }; |
954 | int shift; | 1033 | int shift; |
955 | 1034 | ||
956 | shift = shifts[plane]; | 1035 | shift = shifts[plane]; |
@@ -1027,11 +1106,15 @@ static void dispc_ovl_set_vid_color_conv(enum omap_plane plane, bool enable) | |||
1027 | dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); | 1106 | dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); |
1028 | } | 1107 | } |
1029 | 1108 | ||
1030 | static void dispc_ovl_enable_replication(enum omap_plane plane, bool enable) | 1109 | static void dispc_ovl_enable_replication(enum omap_plane plane, |
1110 | enum omap_overlay_caps caps, bool enable) | ||
1031 | { | 1111 | { |
1032 | static const unsigned shifts[] = { 5, 10, 10, 10 }; | 1112 | static const unsigned shifts[] = { 5, 10, 10, 10 }; |
1033 | int shift; | 1113 | int shift; |
1034 | 1114 | ||
1115 | if ((caps & OMAP_DSS_OVL_CAP_REPLICATION) == 0) | ||
1116 | return; | ||
1117 | |||
1035 | shift = shifts[plane]; | 1118 | shift = shifts[plane]; |
1036 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, shift, shift); | 1119 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, shift, shift); |
1037 | } | 1120 | } |
@@ -1045,10 +1128,10 @@ static void dispc_mgr_set_size(enum omap_channel channel, u16 width, | |||
1045 | dispc_write_reg(DISPC_SIZE_MGR(channel), val); | 1128 | dispc_write_reg(DISPC_SIZE_MGR(channel), val); |
1046 | } | 1129 | } |
1047 | 1130 | ||
1048 | static void dispc_read_plane_fifo_sizes(void) | 1131 | static void dispc_init_fifos(void) |
1049 | { | 1132 | { |
1050 | u32 size; | 1133 | u32 size; |
1051 | int plane; | 1134 | int fifo; |
1052 | u8 start, end; | 1135 | u8 start, end; |
1053 | u32 unit; | 1136 | u32 unit; |
1054 | 1137 | ||
@@ -1056,16 +1139,53 @@ static void dispc_read_plane_fifo_sizes(void) | |||
1056 | 1139 | ||
1057 | dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end); | 1140 | dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end); |
1058 | 1141 | ||
1059 | for (plane = 0; plane < dss_feat_get_num_ovls(); ++plane) { | 1142 | for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) { |
1060 | size = REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(plane), start, end); | 1143 | size = REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(fifo), start, end); |
1061 | size *= unit; | 1144 | size *= unit; |
1062 | dispc.fifo_size[plane] = size; | 1145 | dispc.fifo_size[fifo] = size; |
1146 | |||
1147 | /* | ||
1148 | * By default fifos are mapped directly to overlays, fifo 0 to | ||
1149 | * ovl 0, fifo 1 to ovl 1, etc. | ||
1150 | */ | ||
1151 | dispc.fifo_assignment[fifo] = fifo; | ||
1152 | } | ||
1153 | |||
1154 | /* | ||
1155 | * The GFX fifo on OMAP4 is smaller than the other fifos. The small fifo | ||
1156 | * causes problems with certain use cases, like using the tiler in 2D | ||
1157 | * mode. The below hack swaps the fifos of GFX and WB planes, thus | ||
1158 | * giving GFX plane a larger fifo. WB but should work fine with a | ||
1159 | * smaller fifo. | ||
1160 | */ | ||
1161 | if (dispc.feat->gfx_fifo_workaround) { | ||
1162 | u32 v; | ||
1163 | |||
1164 | v = dispc_read_reg(DISPC_GLOBAL_BUFFER); | ||
1165 | |||
1166 | v = FLD_MOD(v, 4, 2, 0); /* GFX BUF top to WB */ | ||
1167 | v = FLD_MOD(v, 4, 5, 3); /* GFX BUF bottom to WB */ | ||
1168 | v = FLD_MOD(v, 0, 26, 24); /* WB BUF top to GFX */ | ||
1169 | v = FLD_MOD(v, 0, 29, 27); /* WB BUF bottom to GFX */ | ||
1170 | |||
1171 | dispc_write_reg(DISPC_GLOBAL_BUFFER, v); | ||
1172 | |||
1173 | dispc.fifo_assignment[OMAP_DSS_GFX] = OMAP_DSS_WB; | ||
1174 | dispc.fifo_assignment[OMAP_DSS_WB] = OMAP_DSS_GFX; | ||
1063 | } | 1175 | } |
1064 | } | 1176 | } |
1065 | 1177 | ||
1066 | static u32 dispc_ovl_get_fifo_size(enum omap_plane plane) | 1178 | static u32 dispc_ovl_get_fifo_size(enum omap_plane plane) |
1067 | { | 1179 | { |
1068 | return dispc.fifo_size[plane]; | 1180 | int fifo; |
1181 | u32 size = 0; | ||
1182 | |||
1183 | for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) { | ||
1184 | if (dispc.fifo_assignment[fifo] == plane) | ||
1185 | size += dispc.fifo_size[fifo]; | ||
1186 | } | ||
1187 | |||
1188 | return size; | ||
1069 | } | 1189 | } |
1070 | 1190 | ||
1071 | void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high) | 1191 | void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high) |
@@ -1141,6 +1261,14 @@ void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane, | |||
1141 | if (manual_update && dss_has_feature(FEAT_OMAP3_DSI_FIFO_BUG)) { | 1261 | if (manual_update && dss_has_feature(FEAT_OMAP3_DSI_FIFO_BUG)) { |
1142 | *fifo_low = ovl_fifo_size - burst_size * 2; | 1262 | *fifo_low = ovl_fifo_size - burst_size * 2; |
1143 | *fifo_high = total_fifo_size - burst_size; | 1263 | *fifo_high = total_fifo_size - burst_size; |
1264 | } else if (plane == OMAP_DSS_WB) { | ||
1265 | /* | ||
1266 | * Most optimal configuration for writeback is to push out data | ||
1267 | * to the interconnect the moment writeback pushes enough pixels | ||
1268 | * in the FIFO to form a burst | ||
1269 | */ | ||
1270 | *fifo_low = 0; | ||
1271 | *fifo_high = burst_size; | ||
1144 | } else { | 1272 | } else { |
1145 | *fifo_low = ovl_fifo_size - burst_size; | 1273 | *fifo_low = ovl_fifo_size - burst_size; |
1146 | *fifo_high = total_fifo_size - buf_unit; | 1274 | *fifo_high = total_fifo_size - buf_unit; |
@@ -1383,6 +1511,7 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane, | |||
1383 | { | 1511 | { |
1384 | int scale_x = out_width != orig_width; | 1512 | int scale_x = out_width != orig_width; |
1385 | int scale_y = out_height != orig_height; | 1513 | int scale_y = out_height != orig_height; |
1514 | bool chroma_upscale = plane != OMAP_DSS_WB ? true : false; | ||
1386 | 1515 | ||
1387 | if (!dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) | 1516 | if (!dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) |
1388 | return; | 1517 | return; |
@@ -1390,7 +1519,8 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane, | |||
1390 | color_mode != OMAP_DSS_COLOR_UYVY && | 1519 | color_mode != OMAP_DSS_COLOR_UYVY && |
1391 | color_mode != OMAP_DSS_COLOR_NV12)) { | 1520 | color_mode != OMAP_DSS_COLOR_NV12)) { |
1392 | /* reset chroma resampling for RGB formats */ | 1521 | /* reset chroma resampling for RGB formats */ |
1393 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 8, 8); | 1522 | if (plane != OMAP_DSS_WB) |
1523 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 8, 8); | ||
1394 | return; | 1524 | return; |
1395 | } | 1525 | } |
1396 | 1526 | ||
@@ -1399,23 +1529,34 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane, | |||
1399 | 1529 | ||
1400 | switch (color_mode) { | 1530 | switch (color_mode) { |
1401 | case OMAP_DSS_COLOR_NV12: | 1531 | case OMAP_DSS_COLOR_NV12: |
1402 | /* UV is subsampled by 2 vertically*/ | 1532 | if (chroma_upscale) { |
1403 | orig_height >>= 1; | 1533 | /* UV is subsampled by 2 horizontally and vertically */ |
1404 | /* UV is subsampled by 2 horz.*/ | 1534 | orig_height >>= 1; |
1405 | orig_width >>= 1; | 1535 | orig_width >>= 1; |
1536 | } else { | ||
1537 | /* UV is downsampled by 2 horizontally and vertically */ | ||
1538 | orig_height <<= 1; | ||
1539 | orig_width <<= 1; | ||
1540 | } | ||
1541 | |||
1406 | break; | 1542 | break; |
1407 | case OMAP_DSS_COLOR_YUV2: | 1543 | case OMAP_DSS_COLOR_YUV2: |
1408 | case OMAP_DSS_COLOR_UYVY: | 1544 | case OMAP_DSS_COLOR_UYVY: |
1409 | /*For YUV422 with 90/270 rotation, | 1545 | /* For YUV422 with 90/270 rotation, we don't upsample chroma */ |
1410 | *we don't upsample chroma | ||
1411 | */ | ||
1412 | if (rotation == OMAP_DSS_ROT_0 || | 1546 | if (rotation == OMAP_DSS_ROT_0 || |
1413 | rotation == OMAP_DSS_ROT_180) | 1547 | rotation == OMAP_DSS_ROT_180) { |
1414 | /* UV is subsampled by 2 hrz*/ | 1548 | if (chroma_upscale) |
1415 | orig_width >>= 1; | 1549 | /* UV is subsampled by 2 horizontally */ |
1550 | orig_width >>= 1; | ||
1551 | else | ||
1552 | /* UV is downsampled by 2 horizontally */ | ||
1553 | orig_width <<= 1; | ||
1554 | } | ||
1555 | |||
1416 | /* must use FIR for YUV422 if rotated */ | 1556 | /* must use FIR for YUV422 if rotated */ |
1417 | if (rotation != OMAP_DSS_ROT_0) | 1557 | if (rotation != OMAP_DSS_ROT_0) |
1418 | scale_x = scale_y = true; | 1558 | scale_x = scale_y = true; |
1559 | |||
1419 | break; | 1560 | break; |
1420 | default: | 1561 | default: |
1421 | BUG(); | 1562 | BUG(); |
@@ -1431,8 +1572,10 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane, | |||
1431 | out_width, out_height, five_taps, | 1572 | out_width, out_height, five_taps, |
1432 | rotation, DISPC_COLOR_COMPONENT_UV); | 1573 | rotation, DISPC_COLOR_COMPONENT_UV); |
1433 | 1574 | ||
1434 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), | 1575 | if (plane != OMAP_DSS_WB) |
1435 | (scale_x || scale_y) ? 1 : 0, 8, 8); | 1576 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), |
1577 | (scale_x || scale_y) ? 1 : 0, 8, 8); | ||
1578 | |||
1436 | /* set H scaling */ | 1579 | /* set H scaling */ |
1437 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_x ? 1 : 0, 5, 5); | 1580 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_x ? 1 : 0, 5, 5); |
1438 | /* set V scaling */ | 1581 | /* set V scaling */ |
@@ -1848,22 +1991,19 @@ static void calc_tiler_rotation_offset(u16 screen_width, u16 width, | |||
1848 | * This function is used to avoid synclosts in OMAP3, because of some | 1991 | * This function is used to avoid synclosts in OMAP3, because of some |
1849 | * undocumented horizontal position and timing related limitations. | 1992 | * undocumented horizontal position and timing related limitations. |
1850 | */ | 1993 | */ |
1851 | static int check_horiz_timing_omap3(enum omap_channel channel, | 1994 | static int check_horiz_timing_omap3(enum omap_plane plane, |
1852 | const struct omap_video_timings *t, u16 pos_x, | 1995 | const struct omap_video_timings *t, u16 pos_x, |
1853 | u16 width, u16 height, u16 out_width, u16 out_height) | 1996 | u16 width, u16 height, u16 out_width, u16 out_height) |
1854 | { | 1997 | { |
1855 | int DS = DIV_ROUND_UP(height, out_height); | 1998 | int DS = DIV_ROUND_UP(height, out_height); |
1856 | unsigned long nonactive, lclk, pclk; | 1999 | unsigned long nonactive; |
1857 | static const u8 limits[3] = { 8, 10, 20 }; | 2000 | static const u8 limits[3] = { 8, 10, 20 }; |
1858 | u64 val, blank; | 2001 | u64 val, blank; |
2002 | unsigned long pclk = dispc_plane_pclk_rate(plane); | ||
2003 | unsigned long lclk = dispc_plane_lclk_rate(plane); | ||
1859 | int i; | 2004 | int i; |
1860 | 2005 | ||
1861 | nonactive = t->x_res + t->hfp + t->hsw + t->hbp - out_width; | 2006 | nonactive = t->x_res + t->hfp + t->hsw + t->hbp - out_width; |
1862 | pclk = dispc_mgr_pclk_rate(channel); | ||
1863 | if (dss_mgr_is_lcd(channel)) | ||
1864 | lclk = dispc_mgr_lclk_rate(channel); | ||
1865 | else | ||
1866 | lclk = dispc_fclk_rate(); | ||
1867 | 2007 | ||
1868 | i = 0; | 2008 | i = 0; |
1869 | if (out_height < height) | 2009 | if (out_height < height) |
@@ -1900,13 +2040,14 @@ static int check_horiz_timing_omap3(enum omap_channel channel, | |||
1900 | return 0; | 2040 | return 0; |
1901 | } | 2041 | } |
1902 | 2042 | ||
1903 | static unsigned long calc_core_clk_five_taps(enum omap_channel channel, | 2043 | static unsigned long calc_core_clk_five_taps(enum omap_plane plane, |
1904 | const struct omap_video_timings *mgr_timings, u16 width, | 2044 | const struct omap_video_timings *mgr_timings, u16 width, |
1905 | u16 height, u16 out_width, u16 out_height, | 2045 | u16 height, u16 out_width, u16 out_height, |
1906 | enum omap_color_mode color_mode) | 2046 | enum omap_color_mode color_mode) |
1907 | { | 2047 | { |
1908 | u32 core_clk = 0; | 2048 | u32 core_clk = 0; |
1909 | u64 tmp, pclk = dispc_mgr_pclk_rate(channel); | 2049 | u64 tmp; |
2050 | unsigned long pclk = dispc_plane_pclk_rate(plane); | ||
1910 | 2051 | ||
1911 | if (height <= out_height && width <= out_width) | 2052 | if (height <= out_height && width <= out_width) |
1912 | return (unsigned long) pclk; | 2053 | return (unsigned long) pclk; |
@@ -1940,11 +2081,22 @@ static unsigned long calc_core_clk_five_taps(enum omap_channel channel, | |||
1940 | return core_clk; | 2081 | return core_clk; |
1941 | } | 2082 | } |
1942 | 2083 | ||
1943 | static unsigned long calc_core_clk(enum omap_channel channel, u16 width, | 2084 | static unsigned long calc_core_clk_24xx(enum omap_plane plane, u16 width, |
1944 | u16 height, u16 out_width, u16 out_height) | 2085 | u16 height, u16 out_width, u16 out_height, bool mem_to_mem) |
2086 | { | ||
2087 | unsigned long pclk = dispc_plane_pclk_rate(plane); | ||
2088 | |||
2089 | if (height > out_height && width > out_width) | ||
2090 | return pclk * 4; | ||
2091 | else | ||
2092 | return pclk * 2; | ||
2093 | } | ||
2094 | |||
2095 | static unsigned long calc_core_clk_34xx(enum omap_plane plane, u16 width, | ||
2096 | u16 height, u16 out_width, u16 out_height, bool mem_to_mem) | ||
1945 | { | 2097 | { |
1946 | unsigned int hf, vf; | 2098 | unsigned int hf, vf; |
1947 | unsigned long pclk = dispc_mgr_pclk_rate(channel); | 2099 | unsigned long pclk = dispc_plane_pclk_rate(plane); |
1948 | 2100 | ||
1949 | /* | 2101 | /* |
1950 | * FIXME how to determine the 'A' factor | 2102 | * FIXME how to determine the 'A' factor |
@@ -1959,51 +2111,207 @@ static unsigned long calc_core_clk(enum omap_channel channel, u16 width, | |||
1959 | hf = 2; | 2111 | hf = 2; |
1960 | else | 2112 | else |
1961 | hf = 1; | 2113 | hf = 1; |
1962 | |||
1963 | if (height > out_height) | 2114 | if (height > out_height) |
1964 | vf = 2; | 2115 | vf = 2; |
1965 | else | 2116 | else |
1966 | vf = 1; | 2117 | vf = 1; |
1967 | 2118 | ||
1968 | if (cpu_is_omap24xx()) { | 2119 | return pclk * vf * hf; |
1969 | if (vf > 1 && hf > 1) | 2120 | } |
1970 | return pclk * 4; | 2121 | |
1971 | else | 2122 | static unsigned long calc_core_clk_44xx(enum omap_plane plane, u16 width, |
1972 | return pclk * 2; | 2123 | u16 height, u16 out_width, u16 out_height, bool mem_to_mem) |
1973 | } else if (cpu_is_omap34xx()) { | 2124 | { |
1974 | return pclk * vf * hf; | 2125 | unsigned long pclk; |
1975 | } else { | 2126 | |
1976 | if (hf > 1) | 2127 | /* |
1977 | return DIV_ROUND_UP(pclk, out_width) * width; | 2128 | * If the overlay/writeback is in mem to mem mode, there are no |
1978 | else | 2129 | * downscaling limitations with respect to pixel clock, return 1 as |
1979 | return pclk; | 2130 | * required core clock to represent that we have sufficient enough |
2131 | * core clock to do maximum downscaling | ||
2132 | */ | ||
2133 | if (mem_to_mem) | ||
2134 | return 1; | ||
2135 | |||
2136 | pclk = dispc_plane_pclk_rate(plane); | ||
2137 | |||
2138 | if (width > out_width) | ||
2139 | return DIV_ROUND_UP(pclk, out_width) * width; | ||
2140 | else | ||
2141 | return pclk; | ||
2142 | } | ||
2143 | |||
2144 | static int dispc_ovl_calc_scaling_24xx(enum omap_plane plane, | ||
2145 | const struct omap_video_timings *mgr_timings, | ||
2146 | u16 width, u16 height, u16 out_width, u16 out_height, | ||
2147 | enum omap_color_mode color_mode, bool *five_taps, | ||
2148 | int *x_predecim, int *y_predecim, int *decim_x, int *decim_y, | ||
2149 | u16 pos_x, unsigned long *core_clk, bool mem_to_mem) | ||
2150 | { | ||
2151 | int error; | ||
2152 | u16 in_width, in_height; | ||
2153 | int min_factor = min(*decim_x, *decim_y); | ||
2154 | const int maxsinglelinewidth = | ||
2155 | dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); | ||
2156 | |||
2157 | *five_taps = false; | ||
2158 | |||
2159 | do { | ||
2160 | in_height = DIV_ROUND_UP(height, *decim_y); | ||
2161 | in_width = DIV_ROUND_UP(width, *decim_x); | ||
2162 | *core_clk = dispc.feat->calc_core_clk(plane, in_width, | ||
2163 | in_height, out_width, out_height, mem_to_mem); | ||
2164 | error = (in_width > maxsinglelinewidth || !*core_clk || | ||
2165 | *core_clk > dispc_core_clk_rate()); | ||
2166 | if (error) { | ||
2167 | if (*decim_x == *decim_y) { | ||
2168 | *decim_x = min_factor; | ||
2169 | ++*decim_y; | ||
2170 | } else { | ||
2171 | swap(*decim_x, *decim_y); | ||
2172 | if (*decim_x < *decim_y) | ||
2173 | ++*decim_x; | ||
2174 | } | ||
2175 | } | ||
2176 | } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error); | ||
2177 | |||
2178 | if (in_width > maxsinglelinewidth) { | ||
2179 | DSSERR("Cannot scale max input width exceeded"); | ||
2180 | return -EINVAL; | ||
1980 | } | 2181 | } |
2182 | return 0; | ||
1981 | } | 2183 | } |
1982 | 2184 | ||
1983 | static int dispc_ovl_calc_scaling(enum omap_plane plane, | 2185 | static int dispc_ovl_calc_scaling_34xx(enum omap_plane plane, |
1984 | enum omap_channel channel, | ||
1985 | const struct omap_video_timings *mgr_timings, | 2186 | const struct omap_video_timings *mgr_timings, |
1986 | u16 width, u16 height, u16 out_width, u16 out_height, | 2187 | u16 width, u16 height, u16 out_width, u16 out_height, |
1987 | enum omap_color_mode color_mode, bool *five_taps, | 2188 | enum omap_color_mode color_mode, bool *five_taps, |
1988 | int *x_predecim, int *y_predecim, u16 pos_x) | 2189 | int *x_predecim, int *y_predecim, int *decim_x, int *decim_y, |
2190 | u16 pos_x, unsigned long *core_clk, bool mem_to_mem) | ||
1989 | { | 2191 | { |
1990 | struct omap_overlay *ovl = omap_dss_get_overlay(plane); | 2192 | int error; |
1991 | const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); | 2193 | u16 in_width, in_height; |
2194 | int min_factor = min(*decim_x, *decim_y); | ||
2195 | const int maxsinglelinewidth = | ||
2196 | dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); | ||
2197 | |||
2198 | do { | ||
2199 | in_height = DIV_ROUND_UP(height, *decim_y); | ||
2200 | in_width = DIV_ROUND_UP(width, *decim_x); | ||
2201 | *core_clk = calc_core_clk_five_taps(plane, mgr_timings, | ||
2202 | in_width, in_height, out_width, out_height, color_mode); | ||
2203 | |||
2204 | error = check_horiz_timing_omap3(plane, mgr_timings, | ||
2205 | pos_x, in_width, in_height, out_width, | ||
2206 | out_height); | ||
2207 | |||
2208 | if (in_width > maxsinglelinewidth) | ||
2209 | if (in_height > out_height && | ||
2210 | in_height < out_height * 2) | ||
2211 | *five_taps = false; | ||
2212 | if (!*five_taps) | ||
2213 | *core_clk = dispc.feat->calc_core_clk(plane, in_width, | ||
2214 | in_height, out_width, out_height, | ||
2215 | mem_to_mem); | ||
2216 | |||
2217 | error = (error || in_width > maxsinglelinewidth * 2 || | ||
2218 | (in_width > maxsinglelinewidth && *five_taps) || | ||
2219 | !*core_clk || *core_clk > dispc_core_clk_rate()); | ||
2220 | if (error) { | ||
2221 | if (*decim_x == *decim_y) { | ||
2222 | *decim_x = min_factor; | ||
2223 | ++*decim_y; | ||
2224 | } else { | ||
2225 | swap(*decim_x, *decim_y); | ||
2226 | if (*decim_x < *decim_y) | ||
2227 | ++*decim_x; | ||
2228 | } | ||
2229 | } | ||
2230 | } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error); | ||
2231 | |||
2232 | if (check_horiz_timing_omap3(plane, mgr_timings, pos_x, width, height, | ||
2233 | out_width, out_height)){ | ||
2234 | DSSERR("horizontal timing too tight\n"); | ||
2235 | return -EINVAL; | ||
2236 | } | ||
2237 | |||
2238 | if (in_width > (maxsinglelinewidth * 2)) { | ||
2239 | DSSERR("Cannot setup scaling"); | ||
2240 | DSSERR("width exceeds maximum width possible"); | ||
2241 | return -EINVAL; | ||
2242 | } | ||
2243 | |||
2244 | if (in_width > maxsinglelinewidth && *five_taps) { | ||
2245 | DSSERR("cannot setup scaling with five taps"); | ||
2246 | return -EINVAL; | ||
2247 | } | ||
2248 | return 0; | ||
2249 | } | ||
2250 | |||
2251 | static int dispc_ovl_calc_scaling_44xx(enum omap_plane plane, | ||
2252 | const struct omap_video_timings *mgr_timings, | ||
2253 | u16 width, u16 height, u16 out_width, u16 out_height, | ||
2254 | enum omap_color_mode color_mode, bool *five_taps, | ||
2255 | int *x_predecim, int *y_predecim, int *decim_x, int *decim_y, | ||
2256 | u16 pos_x, unsigned long *core_clk, bool mem_to_mem) | ||
2257 | { | ||
2258 | u16 in_width, in_width_max; | ||
2259 | int decim_x_min = *decim_x; | ||
2260 | u16 in_height = DIV_ROUND_UP(height, *decim_y); | ||
1992 | const int maxsinglelinewidth = | 2261 | const int maxsinglelinewidth = |
1993 | dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); | 2262 | dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); |
2263 | unsigned long pclk = dispc_plane_pclk_rate(plane); | ||
2264 | const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); | ||
2265 | |||
2266 | if (mem_to_mem) | ||
2267 | in_width_max = DIV_ROUND_UP(out_width, maxdownscale); | ||
2268 | else | ||
2269 | in_width_max = dispc_core_clk_rate() / | ||
2270 | DIV_ROUND_UP(pclk, out_width); | ||
2271 | |||
2272 | *decim_x = DIV_ROUND_UP(width, in_width_max); | ||
2273 | |||
2274 | *decim_x = *decim_x > decim_x_min ? *decim_x : decim_x_min; | ||
2275 | if (*decim_x > *x_predecim) | ||
2276 | return -EINVAL; | ||
2277 | |||
2278 | do { | ||
2279 | in_width = DIV_ROUND_UP(width, *decim_x); | ||
2280 | } while (*decim_x <= *x_predecim && | ||
2281 | in_width > maxsinglelinewidth && ++*decim_x); | ||
2282 | |||
2283 | if (in_width > maxsinglelinewidth) { | ||
2284 | DSSERR("Cannot scale width exceeds max line width"); | ||
2285 | return -EINVAL; | ||
2286 | } | ||
2287 | |||
2288 | *core_clk = dispc.feat->calc_core_clk(plane, in_width, in_height, | ||
2289 | out_width, out_height, mem_to_mem); | ||
2290 | return 0; | ||
2291 | } | ||
2292 | |||
2293 | static int dispc_ovl_calc_scaling(enum omap_plane plane, | ||
2294 | enum omap_overlay_caps caps, | ||
2295 | const struct omap_video_timings *mgr_timings, | ||
2296 | u16 width, u16 height, u16 out_width, u16 out_height, | ||
2297 | enum omap_color_mode color_mode, bool *five_taps, | ||
2298 | int *x_predecim, int *y_predecim, u16 pos_x, | ||
2299 | enum omap_dss_rotation_type rotation_type, bool mem_to_mem) | ||
2300 | { | ||
2301 | const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); | ||
1994 | const int max_decim_limit = 16; | 2302 | const int max_decim_limit = 16; |
1995 | unsigned long core_clk = 0; | 2303 | unsigned long core_clk = 0; |
1996 | int decim_x, decim_y, error, min_factor; | 2304 | int decim_x, decim_y, ret; |
1997 | u16 in_width, in_height, in_width_max = 0; | ||
1998 | 2305 | ||
1999 | if (width == out_width && height == out_height) | 2306 | if (width == out_width && height == out_height) |
2000 | return 0; | 2307 | return 0; |
2001 | 2308 | ||
2002 | if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) | 2309 | if ((caps & OMAP_DSS_OVL_CAP_SCALE) == 0) |
2003 | return -EINVAL; | 2310 | return -EINVAL; |
2004 | 2311 | ||
2005 | *x_predecim = max_decim_limit; | 2312 | *x_predecim = max_decim_limit; |
2006 | *y_predecim = max_decim_limit; | 2313 | *y_predecim = (rotation_type == OMAP_DSS_ROT_TILER && |
2314 | dss_has_feature(FEAT_BURST_2D)) ? 2 : max_decim_limit; | ||
2007 | 2315 | ||
2008 | if (color_mode == OMAP_DSS_COLOR_CLUT1 || | 2316 | if (color_mode == OMAP_DSS_COLOR_CLUT1 || |
2009 | color_mode == OMAP_DSS_COLOR_CLUT2 || | 2317 | color_mode == OMAP_DSS_COLOR_CLUT2 || |
@@ -2018,118 +2326,18 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane, | |||
2018 | decim_x = DIV_ROUND_UP(DIV_ROUND_UP(width, out_width), maxdownscale); | 2326 | decim_x = DIV_ROUND_UP(DIV_ROUND_UP(width, out_width), maxdownscale); |
2019 | decim_y = DIV_ROUND_UP(DIV_ROUND_UP(height, out_height), maxdownscale); | 2327 | decim_y = DIV_ROUND_UP(DIV_ROUND_UP(height, out_height), maxdownscale); |
2020 | 2328 | ||
2021 | min_factor = min(decim_x, decim_y); | ||
2022 | |||
2023 | if (decim_x > *x_predecim || out_width > width * 8) | 2329 | if (decim_x > *x_predecim || out_width > width * 8) |
2024 | return -EINVAL; | 2330 | return -EINVAL; |
2025 | 2331 | ||
2026 | if (decim_y > *y_predecim || out_height > height * 8) | 2332 | if (decim_y > *y_predecim || out_height > height * 8) |
2027 | return -EINVAL; | 2333 | return -EINVAL; |
2028 | 2334 | ||
2029 | if (cpu_is_omap24xx()) { | 2335 | ret = dispc.feat->calc_scaling(plane, mgr_timings, width, height, |
2030 | *five_taps = false; | 2336 | out_width, out_height, color_mode, five_taps, |
2031 | 2337 | x_predecim, y_predecim, &decim_x, &decim_y, pos_x, &core_clk, | |
2032 | do { | 2338 | mem_to_mem); |
2033 | in_height = DIV_ROUND_UP(height, decim_y); | 2339 | if (ret) |
2034 | in_width = DIV_ROUND_UP(width, decim_x); | 2340 | return ret; |
2035 | core_clk = calc_core_clk(channel, in_width, in_height, | ||
2036 | out_width, out_height); | ||
2037 | error = (in_width > maxsinglelinewidth || !core_clk || | ||
2038 | core_clk > dispc_core_clk_rate()); | ||
2039 | if (error) { | ||
2040 | if (decim_x == decim_y) { | ||
2041 | decim_x = min_factor; | ||
2042 | decim_y++; | ||
2043 | } else { | ||
2044 | swap(decim_x, decim_y); | ||
2045 | if (decim_x < decim_y) | ||
2046 | decim_x++; | ||
2047 | } | ||
2048 | } | ||
2049 | } while (decim_x <= *x_predecim && decim_y <= *y_predecim && | ||
2050 | error); | ||
2051 | |||
2052 | if (in_width > maxsinglelinewidth) { | ||
2053 | DSSERR("Cannot scale max input width exceeded"); | ||
2054 | return -EINVAL; | ||
2055 | } | ||
2056 | } else if (cpu_is_omap34xx()) { | ||
2057 | |||
2058 | do { | ||
2059 | in_height = DIV_ROUND_UP(height, decim_y); | ||
2060 | in_width = DIV_ROUND_UP(width, decim_x); | ||
2061 | core_clk = calc_core_clk_five_taps(channel, mgr_timings, | ||
2062 | in_width, in_height, out_width, out_height, | ||
2063 | color_mode); | ||
2064 | |||
2065 | error = check_horiz_timing_omap3(channel, mgr_timings, | ||
2066 | pos_x, in_width, in_height, out_width, | ||
2067 | out_height); | ||
2068 | |||
2069 | if (in_width > maxsinglelinewidth) | ||
2070 | if (in_height > out_height && | ||
2071 | in_height < out_height * 2) | ||
2072 | *five_taps = false; | ||
2073 | if (!*five_taps) | ||
2074 | core_clk = calc_core_clk(channel, in_width, | ||
2075 | in_height, out_width, out_height); | ||
2076 | error = (error || in_width > maxsinglelinewidth * 2 || | ||
2077 | (in_width > maxsinglelinewidth && *five_taps) || | ||
2078 | !core_clk || core_clk > dispc_core_clk_rate()); | ||
2079 | if (error) { | ||
2080 | if (decim_x == decim_y) { | ||
2081 | decim_x = min_factor; | ||
2082 | decim_y++; | ||
2083 | } else { | ||
2084 | swap(decim_x, decim_y); | ||
2085 | if (decim_x < decim_y) | ||
2086 | decim_x++; | ||
2087 | } | ||
2088 | } | ||
2089 | } while (decim_x <= *x_predecim && decim_y <= *y_predecim | ||
2090 | && error); | ||
2091 | |||
2092 | if (check_horiz_timing_omap3(channel, mgr_timings, pos_x, width, | ||
2093 | height, out_width, out_height)){ | ||
2094 | DSSERR("horizontal timing too tight\n"); | ||
2095 | return -EINVAL; | ||
2096 | } | ||
2097 | |||
2098 | if (in_width > (maxsinglelinewidth * 2)) { | ||
2099 | DSSERR("Cannot setup scaling"); | ||
2100 | DSSERR("width exceeds maximum width possible"); | ||
2101 | return -EINVAL; | ||
2102 | } | ||
2103 | |||
2104 | if (in_width > maxsinglelinewidth && *five_taps) { | ||
2105 | DSSERR("cannot setup scaling with five taps"); | ||
2106 | return -EINVAL; | ||
2107 | } | ||
2108 | } else { | ||
2109 | int decim_x_min = decim_x; | ||
2110 | in_height = DIV_ROUND_UP(height, decim_y); | ||
2111 | in_width_max = dispc_core_clk_rate() / | ||
2112 | DIV_ROUND_UP(dispc_mgr_pclk_rate(channel), | ||
2113 | out_width); | ||
2114 | decim_x = DIV_ROUND_UP(width, in_width_max); | ||
2115 | |||
2116 | decim_x = decim_x > decim_x_min ? decim_x : decim_x_min; | ||
2117 | if (decim_x > *x_predecim) | ||
2118 | return -EINVAL; | ||
2119 | |||
2120 | do { | ||
2121 | in_width = DIV_ROUND_UP(width, decim_x); | ||
2122 | } while (decim_x <= *x_predecim && | ||
2123 | in_width > maxsinglelinewidth && decim_x++); | ||
2124 | |||
2125 | if (in_width > maxsinglelinewidth) { | ||
2126 | DSSERR("Cannot scale width exceeds max line width"); | ||
2127 | return -EINVAL; | ||
2128 | } | ||
2129 | |||
2130 | core_clk = calc_core_clk(channel, in_width, in_height, | ||
2131 | out_width, out_height); | ||
2132 | } | ||
2133 | 2341 | ||
2134 | DSSDBG("required core clk rate = %lu Hz\n", core_clk); | 2342 | DSSDBG("required core clk rate = %lu Hz\n", core_clk); |
2135 | DSSDBG("current core clk rate = %lu Hz\n", dispc_core_clk_rate()); | 2343 | DSSDBG("current core clk rate = %lu Hz\n", dispc_core_clk_rate()); |
@@ -2147,69 +2355,64 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane, | |||
2147 | return 0; | 2355 | return 0; |
2148 | } | 2356 | } |
2149 | 2357 | ||
2150 | int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, | 2358 | static int dispc_ovl_setup_common(enum omap_plane plane, |
2151 | bool replication, const struct omap_video_timings *mgr_timings) | 2359 | enum omap_overlay_caps caps, u32 paddr, u32 p_uv_addr, |
2360 | u16 screen_width, int pos_x, int pos_y, u16 width, u16 height, | ||
2361 | u16 out_width, u16 out_height, enum omap_color_mode color_mode, | ||
2362 | u8 rotation, bool mirror, u8 zorder, u8 pre_mult_alpha, | ||
2363 | u8 global_alpha, enum omap_dss_rotation_type rotation_type, | ||
2364 | bool replication, const struct omap_video_timings *mgr_timings, | ||
2365 | bool mem_to_mem) | ||
2152 | { | 2366 | { |
2153 | struct omap_overlay *ovl = omap_dss_get_overlay(plane); | ||
2154 | bool five_taps = true; | 2367 | bool five_taps = true; |
2155 | bool fieldmode = 0; | 2368 | bool fieldmode = 0; |
2156 | int r, cconv = 0; | 2369 | int r, cconv = 0; |
2157 | unsigned offset0, offset1; | 2370 | unsigned offset0, offset1; |
2158 | s32 row_inc; | 2371 | s32 row_inc; |
2159 | s32 pix_inc; | 2372 | s32 pix_inc; |
2160 | u16 frame_height = oi->height; | 2373 | u16 frame_height = height; |
2161 | unsigned int field_offset = 0; | 2374 | unsigned int field_offset = 0; |
2162 | u16 in_height = oi->height; | 2375 | u16 in_height = height; |
2163 | u16 in_width = oi->width; | 2376 | u16 in_width = width; |
2164 | u16 out_width, out_height; | ||
2165 | enum omap_channel channel; | ||
2166 | int x_predecim = 1, y_predecim = 1; | 2377 | int x_predecim = 1, y_predecim = 1; |
2167 | bool ilace = mgr_timings->interlace; | 2378 | bool ilace = mgr_timings->interlace; |
2168 | 2379 | ||
2169 | channel = dispc_ovl_get_channel_out(plane); | 2380 | if (paddr == 0) |
2170 | |||
2171 | DSSDBG("dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> " | ||
2172 | "%dx%d, cmode %x, rot %d, mir %d, ilace %d chan %d repl %d\n", | ||
2173 | plane, oi->paddr, oi->p_uv_addr, | ||
2174 | oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height, | ||
2175 | oi->out_width, oi->out_height, oi->color_mode, oi->rotation, | ||
2176 | oi->mirror, ilace, channel, replication); | ||
2177 | |||
2178 | if (oi->paddr == 0) | ||
2179 | return -EINVAL; | 2381 | return -EINVAL; |
2180 | 2382 | ||
2181 | out_width = oi->out_width == 0 ? oi->width : oi->out_width; | 2383 | out_width = out_width == 0 ? width : out_width; |
2182 | out_height = oi->out_height == 0 ? oi->height : oi->out_height; | 2384 | out_height = out_height == 0 ? height : out_height; |
2183 | 2385 | ||
2184 | if (ilace && oi->height == out_height) | 2386 | if (ilace && height == out_height) |
2185 | fieldmode = 1; | 2387 | fieldmode = 1; |
2186 | 2388 | ||
2187 | if (ilace) { | 2389 | if (ilace) { |
2188 | if (fieldmode) | 2390 | if (fieldmode) |
2189 | in_height /= 2; | 2391 | in_height /= 2; |
2190 | oi->pos_y /= 2; | 2392 | pos_y /= 2; |
2191 | out_height /= 2; | 2393 | out_height /= 2; |
2192 | 2394 | ||
2193 | DSSDBG("adjusting for ilace: height %d, pos_y %d, " | 2395 | DSSDBG("adjusting for ilace: height %d, pos_y %d, " |
2194 | "out_height %d\n", | 2396 | "out_height %d\n", in_height, pos_y, |
2195 | in_height, oi->pos_y, out_height); | 2397 | out_height); |
2196 | } | 2398 | } |
2197 | 2399 | ||
2198 | if (!dss_feat_color_mode_supported(plane, oi->color_mode)) | 2400 | if (!dss_feat_color_mode_supported(plane, color_mode)) |
2199 | return -EINVAL; | 2401 | return -EINVAL; |
2200 | 2402 | ||
2201 | r = dispc_ovl_calc_scaling(plane, channel, mgr_timings, in_width, | 2403 | r = dispc_ovl_calc_scaling(plane, caps, mgr_timings, in_width, |
2202 | in_height, out_width, out_height, oi->color_mode, | 2404 | in_height, out_width, out_height, color_mode, |
2203 | &five_taps, &x_predecim, &y_predecim, oi->pos_x); | 2405 | &five_taps, &x_predecim, &y_predecim, pos_x, |
2406 | rotation_type, mem_to_mem); | ||
2204 | if (r) | 2407 | if (r) |
2205 | return r; | 2408 | return r; |
2206 | 2409 | ||
2207 | in_width = DIV_ROUND_UP(in_width, x_predecim); | 2410 | in_width = DIV_ROUND_UP(in_width, x_predecim); |
2208 | in_height = DIV_ROUND_UP(in_height, y_predecim); | 2411 | in_height = DIV_ROUND_UP(in_height, y_predecim); |
2209 | 2412 | ||
2210 | if (oi->color_mode == OMAP_DSS_COLOR_YUV2 || | 2413 | if (color_mode == OMAP_DSS_COLOR_YUV2 || |
2211 | oi->color_mode == OMAP_DSS_COLOR_UYVY || | 2414 | color_mode == OMAP_DSS_COLOR_UYVY || |
2212 | oi->color_mode == OMAP_DSS_COLOR_NV12) | 2415 | color_mode == OMAP_DSS_COLOR_NV12) |
2213 | cconv = 1; | 2416 | cconv = 1; |
2214 | 2417 | ||
2215 | if (ilace && !fieldmode) { | 2418 | if (ilace && !fieldmode) { |
@@ -2235,70 +2438,144 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, | |||
2235 | row_inc = 0; | 2438 | row_inc = 0; |
2236 | pix_inc = 0; | 2439 | pix_inc = 0; |
2237 | 2440 | ||
2238 | if (oi->rotation_type == OMAP_DSS_ROT_TILER) | 2441 | if (rotation_type == OMAP_DSS_ROT_TILER) |
2239 | calc_tiler_rotation_offset(oi->screen_width, in_width, | 2442 | calc_tiler_rotation_offset(screen_width, in_width, |
2240 | oi->color_mode, fieldmode, field_offset, | 2443 | color_mode, fieldmode, field_offset, |
2241 | &offset0, &offset1, &row_inc, &pix_inc, | 2444 | &offset0, &offset1, &row_inc, &pix_inc, |
2242 | x_predecim, y_predecim); | 2445 | x_predecim, y_predecim); |
2243 | else if (oi->rotation_type == OMAP_DSS_ROT_DMA) | 2446 | else if (rotation_type == OMAP_DSS_ROT_DMA) |
2244 | calc_dma_rotation_offset(oi->rotation, oi->mirror, | 2447 | calc_dma_rotation_offset(rotation, mirror, |
2245 | oi->screen_width, in_width, frame_height, | 2448 | screen_width, in_width, frame_height, |
2246 | oi->color_mode, fieldmode, field_offset, | 2449 | color_mode, fieldmode, field_offset, |
2247 | &offset0, &offset1, &row_inc, &pix_inc, | 2450 | &offset0, &offset1, &row_inc, &pix_inc, |
2248 | x_predecim, y_predecim); | 2451 | x_predecim, y_predecim); |
2249 | else | 2452 | else |
2250 | calc_vrfb_rotation_offset(oi->rotation, oi->mirror, | 2453 | calc_vrfb_rotation_offset(rotation, mirror, |
2251 | oi->screen_width, in_width, frame_height, | 2454 | screen_width, in_width, frame_height, |
2252 | oi->color_mode, fieldmode, field_offset, | 2455 | color_mode, fieldmode, field_offset, |
2253 | &offset0, &offset1, &row_inc, &pix_inc, | 2456 | &offset0, &offset1, &row_inc, &pix_inc, |
2254 | x_predecim, y_predecim); | 2457 | x_predecim, y_predecim); |
2255 | 2458 | ||
2256 | DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n", | 2459 | DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n", |
2257 | offset0, offset1, row_inc, pix_inc); | 2460 | offset0, offset1, row_inc, pix_inc); |
2258 | 2461 | ||
2259 | dispc_ovl_set_color_mode(plane, oi->color_mode); | 2462 | dispc_ovl_set_color_mode(plane, color_mode); |
2260 | 2463 | ||
2261 | dispc_ovl_configure_burst_type(plane, oi->rotation_type); | 2464 | dispc_ovl_configure_burst_type(plane, rotation_type); |
2262 | 2465 | ||
2263 | dispc_ovl_set_ba0(plane, oi->paddr + offset0); | 2466 | dispc_ovl_set_ba0(plane, paddr + offset0); |
2264 | dispc_ovl_set_ba1(plane, oi->paddr + offset1); | 2467 | dispc_ovl_set_ba1(plane, paddr + offset1); |
2265 | 2468 | ||
2266 | if (OMAP_DSS_COLOR_NV12 == oi->color_mode) { | 2469 | if (OMAP_DSS_COLOR_NV12 == color_mode) { |
2267 | dispc_ovl_set_ba0_uv(plane, oi->p_uv_addr + offset0); | 2470 | dispc_ovl_set_ba0_uv(plane, p_uv_addr + offset0); |
2268 | dispc_ovl_set_ba1_uv(plane, oi->p_uv_addr + offset1); | 2471 | dispc_ovl_set_ba1_uv(plane, p_uv_addr + offset1); |
2269 | } | 2472 | } |
2270 | 2473 | ||
2271 | |||
2272 | dispc_ovl_set_row_inc(plane, row_inc); | 2474 | dispc_ovl_set_row_inc(plane, row_inc); |
2273 | dispc_ovl_set_pix_inc(plane, pix_inc); | 2475 | dispc_ovl_set_pix_inc(plane, pix_inc); |
2274 | 2476 | ||
2275 | DSSDBG("%d,%d %dx%d -> %dx%d\n", oi->pos_x, oi->pos_y, in_width, | 2477 | DSSDBG("%d,%d %dx%d -> %dx%d\n", pos_x, pos_y, in_width, |
2276 | in_height, out_width, out_height); | 2478 | in_height, out_width, out_height); |
2277 | 2479 | ||
2278 | dispc_ovl_set_pos(plane, oi->pos_x, oi->pos_y); | 2480 | dispc_ovl_set_pos(plane, caps, pos_x, pos_y); |
2279 | 2481 | ||
2280 | dispc_ovl_set_pic_size(plane, in_width, in_height); | 2482 | dispc_ovl_set_input_size(plane, in_width, in_height); |
2281 | 2483 | ||
2282 | if (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) { | 2484 | if (caps & OMAP_DSS_OVL_CAP_SCALE) { |
2283 | dispc_ovl_set_scaling(plane, in_width, in_height, out_width, | 2485 | dispc_ovl_set_scaling(plane, in_width, in_height, out_width, |
2284 | out_height, ilace, five_taps, fieldmode, | 2486 | out_height, ilace, five_taps, fieldmode, |
2285 | oi->color_mode, oi->rotation); | 2487 | color_mode, rotation); |
2286 | dispc_ovl_set_vid_size(plane, out_width, out_height); | 2488 | dispc_ovl_set_output_size(plane, out_width, out_height); |
2287 | dispc_ovl_set_vid_color_conv(plane, cconv); | 2489 | dispc_ovl_set_vid_color_conv(plane, cconv); |
2288 | } | 2490 | } |
2289 | 2491 | ||
2290 | dispc_ovl_set_rotation_attrs(plane, oi->rotation, oi->mirror, | 2492 | dispc_ovl_set_rotation_attrs(plane, rotation, mirror, color_mode); |
2291 | oi->color_mode); | ||
2292 | 2493 | ||
2293 | dispc_ovl_set_zorder(plane, oi->zorder); | 2494 | dispc_ovl_set_zorder(plane, caps, zorder); |
2294 | dispc_ovl_set_pre_mult_alpha(plane, oi->pre_mult_alpha); | 2495 | dispc_ovl_set_pre_mult_alpha(plane, caps, pre_mult_alpha); |
2295 | dispc_ovl_setup_global_alpha(plane, oi->global_alpha); | 2496 | dispc_ovl_setup_global_alpha(plane, caps, global_alpha); |
2296 | 2497 | ||
2297 | dispc_ovl_enable_replication(plane, replication); | 2498 | dispc_ovl_enable_replication(plane, caps, replication); |
2298 | 2499 | ||
2299 | return 0; | 2500 | return 0; |
2300 | } | 2501 | } |
2301 | 2502 | ||
2503 | int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi, | ||
2504 | bool replication, const struct omap_video_timings *mgr_timings, | ||
2505 | bool mem_to_mem) | ||
2506 | { | ||
2507 | int r; | ||
2508 | struct omap_overlay *ovl = omap_dss_get_overlay(plane); | ||
2509 | enum omap_channel channel; | ||
2510 | |||
2511 | channel = dispc_ovl_get_channel_out(plane); | ||
2512 | |||
2513 | DSSDBG("dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> " | ||
2514 | "%dx%d, cmode %x, rot %d, mir %d, chan %d repl %d\n", | ||
2515 | plane, oi->paddr, oi->p_uv_addr, oi->screen_width, oi->pos_x, | ||
2516 | oi->pos_y, oi->width, oi->height, oi->out_width, oi->out_height, | ||
2517 | oi->color_mode, oi->rotation, oi->mirror, channel, replication); | ||
2518 | |||
2519 | r = dispc_ovl_setup_common(plane, ovl->caps, oi->paddr, oi->p_uv_addr, | ||
2520 | oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height, | ||
2521 | oi->out_width, oi->out_height, oi->color_mode, oi->rotation, | ||
2522 | oi->mirror, oi->zorder, oi->pre_mult_alpha, oi->global_alpha, | ||
2523 | oi->rotation_type, replication, mgr_timings, mem_to_mem); | ||
2524 | |||
2525 | return r; | ||
2526 | } | ||
2527 | |||
2528 | int dispc_wb_setup(const struct omap_dss_writeback_info *wi, | ||
2529 | bool mem_to_mem, const struct omap_video_timings *mgr_timings) | ||
2530 | { | ||
2531 | int r; | ||
2532 | u32 l; | ||
2533 | enum omap_plane plane = OMAP_DSS_WB; | ||
2534 | const int pos_x = 0, pos_y = 0; | ||
2535 | const u8 zorder = 0, global_alpha = 0; | ||
2536 | const bool replication = false; | ||
2537 | bool truncation; | ||
2538 | int in_width = mgr_timings->x_res; | ||
2539 | int in_height = mgr_timings->y_res; | ||
2540 | enum omap_overlay_caps caps = | ||
2541 | OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA; | ||
2542 | |||
2543 | DSSDBG("dispc_wb_setup, pa %x, pa_uv %x, %d,%d -> %dx%d, cmode %x, " | ||
2544 | "rot %d, mir %d\n", wi->paddr, wi->p_uv_addr, in_width, | ||
2545 | in_height, wi->width, wi->height, wi->color_mode, wi->rotation, | ||
2546 | wi->mirror); | ||
2547 | |||
2548 | r = dispc_ovl_setup_common(plane, caps, wi->paddr, wi->p_uv_addr, | ||
2549 | wi->buf_width, pos_x, pos_y, in_width, in_height, wi->width, | ||
2550 | wi->height, wi->color_mode, wi->rotation, wi->mirror, zorder, | ||
2551 | wi->pre_mult_alpha, global_alpha, wi->rotation_type, | ||
2552 | replication, mgr_timings, mem_to_mem); | ||
2553 | |||
2554 | switch (wi->color_mode) { | ||
2555 | case OMAP_DSS_COLOR_RGB16: | ||
2556 | case OMAP_DSS_COLOR_RGB24P: | ||
2557 | case OMAP_DSS_COLOR_ARGB16: | ||
2558 | case OMAP_DSS_COLOR_RGBA16: | ||
2559 | case OMAP_DSS_COLOR_RGB12U: | ||
2560 | case OMAP_DSS_COLOR_ARGB16_1555: | ||
2561 | case OMAP_DSS_COLOR_XRGB16_1555: | ||
2562 | case OMAP_DSS_COLOR_RGBX16: | ||
2563 | truncation = true; | ||
2564 | break; | ||
2565 | default: | ||
2566 | truncation = false; | ||
2567 | break; | ||
2568 | } | ||
2569 | |||
2570 | /* setup extra DISPC_WB_ATTRIBUTES */ | ||
2571 | l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); | ||
2572 | l = FLD_MOD(l, truncation, 10, 10); /* TRUNCATIONENABLE */ | ||
2573 | l = FLD_MOD(l, mem_to_mem, 19, 19); /* WRITEBACKMODE */ | ||
2574 | dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), l); | ||
2575 | |||
2576 | return r; | ||
2577 | } | ||
2578 | |||
2302 | int dispc_ovl_enable(enum omap_plane plane, bool enable) | 2579 | int dispc_ovl_enable(enum omap_plane plane, bool enable) |
2303 | { | 2580 | { |
2304 | DSSDBG("dispc_enable_plane %d, %d\n", plane, enable); | 2581 | DSSDBG("dispc_enable_plane %d, %d\n", plane, enable); |
@@ -2451,6 +2728,47 @@ void dispc_mgr_enable(enum omap_channel channel, bool enable) | |||
2451 | BUG(); | 2728 | BUG(); |
2452 | } | 2729 | } |
2453 | 2730 | ||
2731 | void dispc_wb_enable(bool enable) | ||
2732 | { | ||
2733 | enum omap_plane plane = OMAP_DSS_WB; | ||
2734 | struct completion frame_done_completion; | ||
2735 | bool is_on; | ||
2736 | int r; | ||
2737 | u32 irq; | ||
2738 | |||
2739 | is_on = REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0); | ||
2740 | irq = DISPC_IRQ_FRAMEDONEWB; | ||
2741 | |||
2742 | if (!enable && is_on) { | ||
2743 | init_completion(&frame_done_completion); | ||
2744 | |||
2745 | r = omap_dispc_register_isr(dispc_disable_isr, | ||
2746 | &frame_done_completion, irq); | ||
2747 | if (r) | ||
2748 | DSSERR("failed to register FRAMEDONEWB isr\n"); | ||
2749 | } | ||
2750 | |||
2751 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0); | ||
2752 | |||
2753 | if (!enable && is_on) { | ||
2754 | if (!wait_for_completion_timeout(&frame_done_completion, | ||
2755 | msecs_to_jiffies(100))) | ||
2756 | DSSERR("timeout waiting for FRAMEDONEWB\n"); | ||
2757 | |||
2758 | r = omap_dispc_unregister_isr(dispc_disable_isr, | ||
2759 | &frame_done_completion, irq); | ||
2760 | if (r) | ||
2761 | DSSERR("failed to unregister FRAMEDONEWB isr\n"); | ||
2762 | } | ||
2763 | } | ||
2764 | |||
2765 | bool dispc_wb_is_enabled(void) | ||
2766 | { | ||
2767 | enum omap_plane plane = OMAP_DSS_WB; | ||
2768 | |||
2769 | return REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0); | ||
2770 | } | ||
2771 | |||
2454 | void dispc_lcd_enable_signal_polarity(bool act_high) | 2772 | void dispc_lcd_enable_signal_polarity(bool act_high) |
2455 | { | 2773 | { |
2456 | if (!dss_has_feature(FEAT_LCDENABLEPOL)) | 2774 | if (!dss_has_feature(FEAT_LCDENABLEPOL)) |
@@ -2605,24 +2923,13 @@ static bool _dispc_mgr_size_ok(u16 width, u16 height) | |||
2605 | static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp, | 2923 | static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp, |
2606 | int vsw, int vfp, int vbp) | 2924 | int vsw, int vfp, int vbp) |
2607 | { | 2925 | { |
2608 | if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) { | 2926 | if (hsw < 1 || hsw > dispc.feat->sw_max || |
2609 | if (hsw < 1 || hsw > 64 || | 2927 | hfp < 1 || hfp > dispc.feat->hp_max || |
2610 | hfp < 1 || hfp > 256 || | 2928 | hbp < 1 || hbp > dispc.feat->hp_max || |
2611 | hbp < 1 || hbp > 256 || | 2929 | vsw < 1 || vsw > dispc.feat->sw_max || |
2612 | vsw < 1 || vsw > 64 || | 2930 | vfp < 0 || vfp > dispc.feat->vp_max || |
2613 | vfp < 0 || vfp > 255 || | 2931 | vbp < 0 || vbp > dispc.feat->vp_max) |
2614 | vbp < 0 || vbp > 255) | 2932 | return false; |
2615 | return false; | ||
2616 | } else { | ||
2617 | if (hsw < 1 || hsw > 256 || | ||
2618 | hfp < 1 || hfp > 4096 || | ||
2619 | hbp < 1 || hbp > 4096 || | ||
2620 | vsw < 1 || vsw > 256 || | ||
2621 | vfp < 0 || vfp > 4095 || | ||
2622 | vbp < 0 || vbp > 4095) | ||
2623 | return false; | ||
2624 | } | ||
2625 | |||
2626 | return true; | 2933 | return true; |
2627 | } | 2934 | } |
2628 | 2935 | ||
@@ -2654,19 +2961,12 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw, | |||
2654 | u32 timing_h, timing_v, l; | 2961 | u32 timing_h, timing_v, l; |
2655 | bool onoff, rf, ipc; | 2962 | bool onoff, rf, ipc; |
2656 | 2963 | ||
2657 | if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) { | 2964 | timing_h = FLD_VAL(hsw-1, dispc.feat->sw_start, 0) | |
2658 | timing_h = FLD_VAL(hsw-1, 5, 0) | FLD_VAL(hfp-1, 15, 8) | | 2965 | FLD_VAL(hfp-1, dispc.feat->fp_start, 8) | |
2659 | FLD_VAL(hbp-1, 27, 20); | 2966 | FLD_VAL(hbp-1, dispc.feat->bp_start, 20); |
2660 | 2967 | timing_v = FLD_VAL(vsw-1, dispc.feat->sw_start, 0) | | |
2661 | timing_v = FLD_VAL(vsw-1, 5, 0) | FLD_VAL(vfp, 15, 8) | | 2968 | FLD_VAL(vfp, dispc.feat->fp_start, 8) | |
2662 | FLD_VAL(vbp, 27, 20); | 2969 | FLD_VAL(vbp, dispc.feat->bp_start, 20); |
2663 | } else { | ||
2664 | timing_h = FLD_VAL(hsw-1, 7, 0) | FLD_VAL(hfp-1, 19, 8) | | ||
2665 | FLD_VAL(hbp-1, 31, 20); | ||
2666 | |||
2667 | timing_v = FLD_VAL(vsw-1, 7, 0) | FLD_VAL(vfp, 19, 8) | | ||
2668 | FLD_VAL(vbp, 31, 20); | ||
2669 | } | ||
2670 | 2970 | ||
2671 | dispc_write_reg(DISPC_TIMING_H(channel), timing_h); | 2971 | dispc_write_reg(DISPC_TIMING_H(channel), timing_h); |
2672 | dispc_write_reg(DISPC_TIMING_V(channel), timing_v); | 2972 | dispc_write_reg(DISPC_TIMING_V(channel), timing_v); |
@@ -2872,6 +3172,23 @@ unsigned long dispc_core_clk_rate(void) | |||
2872 | return fclk / lcd; | 3172 | return fclk / lcd; |
2873 | } | 3173 | } |
2874 | 3174 | ||
3175 | static unsigned long dispc_plane_pclk_rate(enum omap_plane plane) | ||
3176 | { | ||
3177 | enum omap_channel channel = dispc_ovl_get_channel_out(plane); | ||
3178 | |||
3179 | return dispc_mgr_pclk_rate(channel); | ||
3180 | } | ||
3181 | |||
3182 | static unsigned long dispc_plane_lclk_rate(enum omap_plane plane) | ||
3183 | { | ||
3184 | enum omap_channel channel = dispc_ovl_get_channel_out(plane); | ||
3185 | |||
3186 | if (dss_mgr_is_lcd(channel)) | ||
3187 | return dispc_mgr_lclk_rate(channel); | ||
3188 | else | ||
3189 | return dispc_fclk_rate(); | ||
3190 | |||
3191 | } | ||
2875 | static void dispc_dump_clocks_channel(struct seq_file *s, enum omap_channel channel) | 3192 | static void dispc_dump_clocks_channel(struct seq_file *s, enum omap_channel channel) |
2876 | { | 3193 | { |
2877 | int lcd, pcd; | 3194 | int lcd, pcd; |
@@ -3492,7 +3809,7 @@ static void dispc_error_worker(struct work_struct *work) | |||
3492 | ovl->name); | 3809 | ovl->name); |
3493 | dispc_ovl_enable(ovl->id, false); | 3810 | dispc_ovl_enable(ovl->id, false); |
3494 | dispc_mgr_go(ovl->manager->id); | 3811 | dispc_mgr_go(ovl->manager->id); |
3495 | mdelay(50); | 3812 | msleep(50); |
3496 | } | 3813 | } |
3497 | } | 3814 | } |
3498 | 3815 | ||
@@ -3504,7 +3821,7 @@ static void dispc_error_worker(struct work_struct *work) | |||
3504 | bit = mgr_desc[i].sync_lost_irq; | 3821 | bit = mgr_desc[i].sync_lost_irq; |
3505 | 3822 | ||
3506 | if (bit & errors) { | 3823 | if (bit & errors) { |
3507 | struct omap_dss_device *dssdev = mgr->device; | 3824 | struct omap_dss_device *dssdev = mgr->get_device(mgr); |
3508 | bool enable; | 3825 | bool enable; |
3509 | 3826 | ||
3510 | DSSERR("SYNC_LOST on channel %s, restarting the output " | 3827 | DSSERR("SYNC_LOST on channel %s, restarting the output " |
@@ -3524,7 +3841,7 @@ static void dispc_error_worker(struct work_struct *work) | |||
3524 | } | 3841 | } |
3525 | 3842 | ||
3526 | dispc_mgr_go(mgr->id); | 3843 | dispc_mgr_go(mgr->id); |
3527 | mdelay(50); | 3844 | msleep(50); |
3528 | 3845 | ||
3529 | if (enable) | 3846 | if (enable) |
3530 | dssdev->driver->enable(dssdev); | 3847 | dssdev->driver->enable(dssdev); |
@@ -3535,9 +3852,13 @@ static void dispc_error_worker(struct work_struct *work) | |||
3535 | DSSERR("OCP_ERR\n"); | 3852 | DSSERR("OCP_ERR\n"); |
3536 | for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { | 3853 | for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { |
3537 | struct omap_overlay_manager *mgr; | 3854 | struct omap_overlay_manager *mgr; |
3855 | struct omap_dss_device *dssdev; | ||
3856 | |||
3538 | mgr = omap_dss_get_overlay_manager(i); | 3857 | mgr = omap_dss_get_overlay_manager(i); |
3539 | if (mgr->device && mgr->device->driver) | 3858 | dssdev = mgr->get_device(mgr); |
3540 | mgr->device->driver->disable(mgr->device); | 3859 | |
3860 | if (dssdev && dssdev->driver) | ||
3861 | dssdev->driver->disable(dssdev); | ||
3541 | } | 3862 | } |
3542 | } | 3863 | } |
3543 | 3864 | ||
@@ -3661,17 +3982,98 @@ static void _omap_dispc_initial_config(void) | |||
3661 | if (dss_has_feature(FEAT_FUNCGATED)) | 3982 | if (dss_has_feature(FEAT_FUNCGATED)) |
3662 | REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9); | 3983 | REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9); |
3663 | 3984 | ||
3664 | _dispc_setup_color_conv_coef(); | 3985 | dispc_setup_color_conv_coef(); |
3665 | 3986 | ||
3666 | dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY); | 3987 | dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY); |
3667 | 3988 | ||
3668 | dispc_read_plane_fifo_sizes(); | 3989 | dispc_init_fifos(); |
3669 | 3990 | ||
3670 | dispc_configure_burst_sizes(); | 3991 | dispc_configure_burst_sizes(); |
3671 | 3992 | ||
3672 | dispc_ovl_enable_zorder_planes(); | 3993 | dispc_ovl_enable_zorder_planes(); |
3673 | } | 3994 | } |
3674 | 3995 | ||
3996 | static const struct dispc_features omap24xx_dispc_feats __initconst = { | ||
3997 | .sw_start = 5, | ||
3998 | .fp_start = 15, | ||
3999 | .bp_start = 27, | ||
4000 | .sw_max = 64, | ||
4001 | .vp_max = 255, | ||
4002 | .hp_max = 256, | ||
4003 | .calc_scaling = dispc_ovl_calc_scaling_24xx, | ||
4004 | .calc_core_clk = calc_core_clk_24xx, | ||
4005 | .num_fifos = 3, | ||
4006 | }; | ||
4007 | |||
4008 | static const struct dispc_features omap34xx_rev1_0_dispc_feats __initconst = { | ||
4009 | .sw_start = 5, | ||
4010 | .fp_start = 15, | ||
4011 | .bp_start = 27, | ||
4012 | .sw_max = 64, | ||
4013 | .vp_max = 255, | ||
4014 | .hp_max = 256, | ||
4015 | .calc_scaling = dispc_ovl_calc_scaling_34xx, | ||
4016 | .calc_core_clk = calc_core_clk_34xx, | ||
4017 | .num_fifos = 3, | ||
4018 | }; | ||
4019 | |||
4020 | static const struct dispc_features omap34xx_rev3_0_dispc_feats __initconst = { | ||
4021 | .sw_start = 7, | ||
4022 | .fp_start = 19, | ||
4023 | .bp_start = 31, | ||
4024 | .sw_max = 256, | ||
4025 | .vp_max = 4095, | ||
4026 | .hp_max = 4096, | ||
4027 | .calc_scaling = dispc_ovl_calc_scaling_34xx, | ||
4028 | .calc_core_clk = calc_core_clk_34xx, | ||
4029 | .num_fifos = 3, | ||
4030 | }; | ||
4031 | |||
4032 | static const struct dispc_features omap44xx_dispc_feats __initconst = { | ||
4033 | .sw_start = 7, | ||
4034 | .fp_start = 19, | ||
4035 | .bp_start = 31, | ||
4036 | .sw_max = 256, | ||
4037 | .vp_max = 4095, | ||
4038 | .hp_max = 4096, | ||
4039 | .calc_scaling = dispc_ovl_calc_scaling_44xx, | ||
4040 | .calc_core_clk = calc_core_clk_44xx, | ||
4041 | .num_fifos = 5, | ||
4042 | .gfx_fifo_workaround = true, | ||
4043 | }; | ||
4044 | |||
4045 | static int __init dispc_init_features(struct device *dev) | ||
4046 | { | ||
4047 | const struct dispc_features *src; | ||
4048 | struct dispc_features *dst; | ||
4049 | |||
4050 | dst = devm_kzalloc(dev, sizeof(*dst), GFP_KERNEL); | ||
4051 | if (!dst) { | ||
4052 | dev_err(dev, "Failed to allocate DISPC Features\n"); | ||
4053 | return -ENOMEM; | ||
4054 | } | ||
4055 | |||
4056 | if (cpu_is_omap24xx()) { | ||
4057 | src = &omap24xx_dispc_feats; | ||
4058 | } else if (cpu_is_omap34xx()) { | ||
4059 | if (omap_rev() < OMAP3430_REV_ES3_0) | ||
4060 | src = &omap34xx_rev1_0_dispc_feats; | ||
4061 | else | ||
4062 | src = &omap34xx_rev3_0_dispc_feats; | ||
4063 | } else if (cpu_is_omap44xx()) { | ||
4064 | src = &omap44xx_dispc_feats; | ||
4065 | } else if (soc_is_omap54xx()) { | ||
4066 | src = &omap44xx_dispc_feats; | ||
4067 | } else { | ||
4068 | return -ENODEV; | ||
4069 | } | ||
4070 | |||
4071 | memcpy(dst, src, sizeof(*dst)); | ||
4072 | dispc.feat = dst; | ||
4073 | |||
4074 | return 0; | ||
4075 | } | ||
4076 | |||
3675 | /* DISPC HW IP initialisation */ | 4077 | /* DISPC HW IP initialisation */ |
3676 | static int __init omap_dispchw_probe(struct platform_device *pdev) | 4078 | static int __init omap_dispchw_probe(struct platform_device *pdev) |
3677 | { | 4079 | { |
@@ -3682,6 +4084,10 @@ static int __init omap_dispchw_probe(struct platform_device *pdev) | |||
3682 | 4084 | ||
3683 | dispc.pdev = pdev; | 4085 | dispc.pdev = pdev; |
3684 | 4086 | ||
4087 | r = dispc_init_features(&dispc.pdev->dev); | ||
4088 | if (r) | ||
4089 | return r; | ||
4090 | |||
3685 | spin_lock_init(&dispc.irq_lock); | 4091 | spin_lock_init(&dispc.irq_lock); |
3686 | 4092 | ||
3687 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS | 4093 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS |
diff --git a/drivers/video/omap2/dss/dispc.h b/drivers/video/omap2/dss/dispc.h index 92d8a9be86fc..222363c6e623 100644 --- a/drivers/video/omap2/dss/dispc.h +++ b/drivers/video/omap2/dss/dispc.h | |||
@@ -36,6 +36,7 @@ | |||
36 | #define DISPC_CONTROL2 0x0238 | 36 | #define DISPC_CONTROL2 0x0238 |
37 | #define DISPC_CONFIG2 0x0620 | 37 | #define DISPC_CONFIG2 0x0620 |
38 | #define DISPC_DIVISOR 0x0804 | 38 | #define DISPC_DIVISOR 0x0804 |
39 | #define DISPC_GLOBAL_BUFFER 0x0800 | ||
39 | #define DISPC_CONTROL3 0x0848 | 40 | #define DISPC_CONTROL3 0x0848 |
40 | #define DISPC_CONFIG3 0x084C | 41 | #define DISPC_CONFIG3 0x084C |
41 | 42 | ||
@@ -355,6 +356,8 @@ static inline u16 DISPC_OVL_BASE(enum omap_plane plane) | |||
355 | return 0x014C; | 356 | return 0x014C; |
356 | case OMAP_DSS_VIDEO3: | 357 | case OMAP_DSS_VIDEO3: |
357 | return 0x0300; | 358 | return 0x0300; |
359 | case OMAP_DSS_WB: | ||
360 | return 0x0500; | ||
358 | default: | 361 | default: |
359 | BUG(); | 362 | BUG(); |
360 | return 0; | 363 | return 0; |
@@ -370,6 +373,7 @@ static inline u16 DISPC_BA0_OFFSET(enum omap_plane plane) | |||
370 | case OMAP_DSS_VIDEO2: | 373 | case OMAP_DSS_VIDEO2: |
371 | return 0x0000; | 374 | return 0x0000; |
372 | case OMAP_DSS_VIDEO3: | 375 | case OMAP_DSS_VIDEO3: |
376 | case OMAP_DSS_WB: | ||
373 | return 0x0008; | 377 | return 0x0008; |
374 | default: | 378 | default: |
375 | BUG(); | 379 | BUG(); |
@@ -385,6 +389,7 @@ static inline u16 DISPC_BA1_OFFSET(enum omap_plane plane) | |||
385 | case OMAP_DSS_VIDEO2: | 389 | case OMAP_DSS_VIDEO2: |
386 | return 0x0004; | 390 | return 0x0004; |
387 | case OMAP_DSS_VIDEO3: | 391 | case OMAP_DSS_VIDEO3: |
392 | case OMAP_DSS_WB: | ||
388 | return 0x000C; | 393 | return 0x000C; |
389 | default: | 394 | default: |
390 | BUG(); | 395 | BUG(); |
@@ -404,6 +409,8 @@ static inline u16 DISPC_BA0_UV_OFFSET(enum omap_plane plane) | |||
404 | return 0x04BC; | 409 | return 0x04BC; |
405 | case OMAP_DSS_VIDEO3: | 410 | case OMAP_DSS_VIDEO3: |
406 | return 0x0310; | 411 | return 0x0310; |
412 | case OMAP_DSS_WB: | ||
413 | return 0x0118; | ||
407 | default: | 414 | default: |
408 | BUG(); | 415 | BUG(); |
409 | return 0; | 416 | return 0; |
@@ -422,6 +429,8 @@ static inline u16 DISPC_BA1_UV_OFFSET(enum omap_plane plane) | |||
422 | return 0x04C0; | 429 | return 0x04C0; |
423 | case OMAP_DSS_VIDEO3: | 430 | case OMAP_DSS_VIDEO3: |
424 | return 0x0314; | 431 | return 0x0314; |
432 | case OMAP_DSS_WB: | ||
433 | return 0x011C; | ||
425 | default: | 434 | default: |
426 | BUG(); | 435 | BUG(); |
427 | return 0; | 436 | return 0; |
@@ -451,6 +460,7 @@ static inline u16 DISPC_SIZE_OFFSET(enum omap_plane plane) | |||
451 | case OMAP_DSS_VIDEO2: | 460 | case OMAP_DSS_VIDEO2: |
452 | return 0x000C; | 461 | return 0x000C; |
453 | case OMAP_DSS_VIDEO3: | 462 | case OMAP_DSS_VIDEO3: |
463 | case OMAP_DSS_WB: | ||
454 | return 0x00A8; | 464 | return 0x00A8; |
455 | default: | 465 | default: |
456 | BUG(); | 466 | BUG(); |
@@ -467,6 +477,7 @@ static inline u16 DISPC_ATTR_OFFSET(enum omap_plane plane) | |||
467 | case OMAP_DSS_VIDEO2: | 477 | case OMAP_DSS_VIDEO2: |
468 | return 0x0010; | 478 | return 0x0010; |
469 | case OMAP_DSS_VIDEO3: | 479 | case OMAP_DSS_VIDEO3: |
480 | case OMAP_DSS_WB: | ||
470 | return 0x0070; | 481 | return 0x0070; |
471 | default: | 482 | default: |
472 | BUG(); | 483 | BUG(); |
@@ -486,6 +497,8 @@ static inline u16 DISPC_ATTR2_OFFSET(enum omap_plane plane) | |||
486 | return 0x04DC; | 497 | return 0x04DC; |
487 | case OMAP_DSS_VIDEO3: | 498 | case OMAP_DSS_VIDEO3: |
488 | return 0x032C; | 499 | return 0x032C; |
500 | case OMAP_DSS_WB: | ||
501 | return 0x0310; | ||
489 | default: | 502 | default: |
490 | BUG(); | 503 | BUG(); |
491 | return 0; | 504 | return 0; |
@@ -501,6 +514,7 @@ static inline u16 DISPC_FIFO_THRESH_OFFSET(enum omap_plane plane) | |||
501 | case OMAP_DSS_VIDEO2: | 514 | case OMAP_DSS_VIDEO2: |
502 | return 0x0014; | 515 | return 0x0014; |
503 | case OMAP_DSS_VIDEO3: | 516 | case OMAP_DSS_VIDEO3: |
517 | case OMAP_DSS_WB: | ||
504 | return 0x008C; | 518 | return 0x008C; |
505 | default: | 519 | default: |
506 | BUG(); | 520 | BUG(); |
@@ -517,6 +531,7 @@ static inline u16 DISPC_FIFO_SIZE_STATUS_OFFSET(enum omap_plane plane) | |||
517 | case OMAP_DSS_VIDEO2: | 531 | case OMAP_DSS_VIDEO2: |
518 | return 0x0018; | 532 | return 0x0018; |
519 | case OMAP_DSS_VIDEO3: | 533 | case OMAP_DSS_VIDEO3: |
534 | case OMAP_DSS_WB: | ||
520 | return 0x0088; | 535 | return 0x0088; |
521 | default: | 536 | default: |
522 | BUG(); | 537 | BUG(); |
@@ -533,6 +548,7 @@ static inline u16 DISPC_ROW_INC_OFFSET(enum omap_plane plane) | |||
533 | case OMAP_DSS_VIDEO2: | 548 | case OMAP_DSS_VIDEO2: |
534 | return 0x001C; | 549 | return 0x001C; |
535 | case OMAP_DSS_VIDEO3: | 550 | case OMAP_DSS_VIDEO3: |
551 | case OMAP_DSS_WB: | ||
536 | return 0x00A4; | 552 | return 0x00A4; |
537 | default: | 553 | default: |
538 | BUG(); | 554 | BUG(); |
@@ -549,6 +565,7 @@ static inline u16 DISPC_PIX_INC_OFFSET(enum omap_plane plane) | |||
549 | case OMAP_DSS_VIDEO2: | 565 | case OMAP_DSS_VIDEO2: |
550 | return 0x0020; | 566 | return 0x0020; |
551 | case OMAP_DSS_VIDEO3: | 567 | case OMAP_DSS_VIDEO3: |
568 | case OMAP_DSS_WB: | ||
552 | return 0x0098; | 569 | return 0x0098; |
553 | default: | 570 | default: |
554 | BUG(); | 571 | BUG(); |
@@ -598,6 +615,7 @@ static inline u16 DISPC_FIR_OFFSET(enum omap_plane plane) | |||
598 | case OMAP_DSS_VIDEO2: | 615 | case OMAP_DSS_VIDEO2: |
599 | return 0x0024; | 616 | return 0x0024; |
600 | case OMAP_DSS_VIDEO3: | 617 | case OMAP_DSS_VIDEO3: |
618 | case OMAP_DSS_WB: | ||
601 | return 0x0090; | 619 | return 0x0090; |
602 | default: | 620 | default: |
603 | BUG(); | 621 | BUG(); |
@@ -617,6 +635,8 @@ static inline u16 DISPC_FIR2_OFFSET(enum omap_plane plane) | |||
617 | return 0x055C; | 635 | return 0x055C; |
618 | case OMAP_DSS_VIDEO3: | 636 | case OMAP_DSS_VIDEO3: |
619 | return 0x0424; | 637 | return 0x0424; |
638 | case OMAP_DSS_WB: | ||
639 | return 0x290; | ||
620 | default: | 640 | default: |
621 | BUG(); | 641 | BUG(); |
622 | return 0; | 642 | return 0; |
@@ -633,6 +653,7 @@ static inline u16 DISPC_PIC_SIZE_OFFSET(enum omap_plane plane) | |||
633 | case OMAP_DSS_VIDEO2: | 653 | case OMAP_DSS_VIDEO2: |
634 | return 0x0028; | 654 | return 0x0028; |
635 | case OMAP_DSS_VIDEO3: | 655 | case OMAP_DSS_VIDEO3: |
656 | case OMAP_DSS_WB: | ||
636 | return 0x0094; | 657 | return 0x0094; |
637 | default: | 658 | default: |
638 | BUG(); | 659 | BUG(); |
@@ -651,6 +672,7 @@ static inline u16 DISPC_ACCU0_OFFSET(enum omap_plane plane) | |||
651 | case OMAP_DSS_VIDEO2: | 672 | case OMAP_DSS_VIDEO2: |
652 | return 0x002C; | 673 | return 0x002C; |
653 | case OMAP_DSS_VIDEO3: | 674 | case OMAP_DSS_VIDEO3: |
675 | case OMAP_DSS_WB: | ||
654 | return 0x0000; | 676 | return 0x0000; |
655 | default: | 677 | default: |
656 | BUG(); | 678 | BUG(); |
@@ -670,6 +692,8 @@ static inline u16 DISPC_ACCU2_0_OFFSET(enum omap_plane plane) | |||
670 | return 0x0560; | 692 | return 0x0560; |
671 | case OMAP_DSS_VIDEO3: | 693 | case OMAP_DSS_VIDEO3: |
672 | return 0x0428; | 694 | return 0x0428; |
695 | case OMAP_DSS_WB: | ||
696 | return 0x0294; | ||
673 | default: | 697 | default: |
674 | BUG(); | 698 | BUG(); |
675 | return 0; | 699 | return 0; |
@@ -686,6 +710,7 @@ static inline u16 DISPC_ACCU1_OFFSET(enum omap_plane plane) | |||
686 | case OMAP_DSS_VIDEO2: | 710 | case OMAP_DSS_VIDEO2: |
687 | return 0x0030; | 711 | return 0x0030; |
688 | case OMAP_DSS_VIDEO3: | 712 | case OMAP_DSS_VIDEO3: |
713 | case OMAP_DSS_WB: | ||
689 | return 0x0004; | 714 | return 0x0004; |
690 | default: | 715 | default: |
691 | BUG(); | 716 | BUG(); |
@@ -705,6 +730,8 @@ static inline u16 DISPC_ACCU2_1_OFFSET(enum omap_plane plane) | |||
705 | return 0x0564; | 730 | return 0x0564; |
706 | case OMAP_DSS_VIDEO3: | 731 | case OMAP_DSS_VIDEO3: |
707 | return 0x042C; | 732 | return 0x042C; |
733 | case OMAP_DSS_WB: | ||
734 | return 0x0298; | ||
708 | default: | 735 | default: |
709 | BUG(); | 736 | BUG(); |
710 | return 0; | 737 | return 0; |
@@ -722,6 +749,7 @@ static inline u16 DISPC_FIR_COEF_H_OFFSET(enum omap_plane plane, u16 i) | |||
722 | case OMAP_DSS_VIDEO2: | 749 | case OMAP_DSS_VIDEO2: |
723 | return 0x0034 + i * 0x8; | 750 | return 0x0034 + i * 0x8; |
724 | case OMAP_DSS_VIDEO3: | 751 | case OMAP_DSS_VIDEO3: |
752 | case OMAP_DSS_WB: | ||
725 | return 0x0010 + i * 0x8; | 753 | return 0x0010 + i * 0x8; |
726 | default: | 754 | default: |
727 | BUG(); | 755 | BUG(); |
@@ -742,6 +770,8 @@ static inline u16 DISPC_FIR_COEF_H2_OFFSET(enum omap_plane plane, u16 i) | |||
742 | return 0x0568 + i * 0x8; | 770 | return 0x0568 + i * 0x8; |
743 | case OMAP_DSS_VIDEO3: | 771 | case OMAP_DSS_VIDEO3: |
744 | return 0x0430 + i * 0x8; | 772 | return 0x0430 + i * 0x8; |
773 | case OMAP_DSS_WB: | ||
774 | return 0x02A0 + i * 0x8; | ||
745 | default: | 775 | default: |
746 | BUG(); | 776 | BUG(); |
747 | return 0; | 777 | return 0; |
@@ -759,6 +789,7 @@ static inline u16 DISPC_FIR_COEF_HV_OFFSET(enum omap_plane plane, u16 i) | |||
759 | case OMAP_DSS_VIDEO2: | 789 | case OMAP_DSS_VIDEO2: |
760 | return 0x0038 + i * 0x8; | 790 | return 0x0038 + i * 0x8; |
761 | case OMAP_DSS_VIDEO3: | 791 | case OMAP_DSS_VIDEO3: |
792 | case OMAP_DSS_WB: | ||
762 | return 0x0014 + i * 0x8; | 793 | return 0x0014 + i * 0x8; |
763 | default: | 794 | default: |
764 | BUG(); | 795 | BUG(); |
@@ -779,6 +810,8 @@ static inline u16 DISPC_FIR_COEF_HV2_OFFSET(enum omap_plane plane, u16 i) | |||
779 | return 0x056C + i * 0x8; | 810 | return 0x056C + i * 0x8; |
780 | case OMAP_DSS_VIDEO3: | 811 | case OMAP_DSS_VIDEO3: |
781 | return 0x0434 + i * 0x8; | 812 | return 0x0434 + i * 0x8; |
813 | case OMAP_DSS_WB: | ||
814 | return 0x02A4 + i * 0x8; | ||
782 | default: | 815 | default: |
783 | BUG(); | 816 | BUG(); |
784 | return 0; | 817 | return 0; |
@@ -795,6 +828,7 @@ static inline u16 DISPC_CONV_COEF_OFFSET(enum omap_plane plane, u16 i) | |||
795 | case OMAP_DSS_VIDEO1: | 828 | case OMAP_DSS_VIDEO1: |
796 | case OMAP_DSS_VIDEO2: | 829 | case OMAP_DSS_VIDEO2: |
797 | case OMAP_DSS_VIDEO3: | 830 | case OMAP_DSS_VIDEO3: |
831 | case OMAP_DSS_WB: | ||
798 | return 0x0074 + i * 0x4; | 832 | return 0x0074 + i * 0x4; |
799 | default: | 833 | default: |
800 | BUG(); | 834 | BUG(); |
@@ -814,6 +848,7 @@ static inline u16 DISPC_FIR_COEF_V_OFFSET(enum omap_plane plane, u16 i) | |||
814 | case OMAP_DSS_VIDEO2: | 848 | case OMAP_DSS_VIDEO2: |
815 | return 0x00B4 + i * 0x4; | 849 | return 0x00B4 + i * 0x4; |
816 | case OMAP_DSS_VIDEO3: | 850 | case OMAP_DSS_VIDEO3: |
851 | case OMAP_DSS_WB: | ||
817 | return 0x0050 + i * 0x4; | 852 | return 0x0050 + i * 0x4; |
818 | default: | 853 | default: |
819 | BUG(); | 854 | BUG(); |
@@ -834,6 +869,8 @@ static inline u16 DISPC_FIR_COEF_V2_OFFSET(enum omap_plane plane, u16 i) | |||
834 | return 0x05A8 + i * 0x4; | 869 | return 0x05A8 + i * 0x4; |
835 | case OMAP_DSS_VIDEO3: | 870 | case OMAP_DSS_VIDEO3: |
836 | return 0x0470 + i * 0x4; | 871 | return 0x0470 + i * 0x4; |
872 | case OMAP_DSS_WB: | ||
873 | return 0x02E0 + i * 0x4; | ||
837 | default: | 874 | default: |
838 | BUG(); | 875 | BUG(); |
839 | return 0; | 876 | return 0; |
diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c index 5bd957e85505..ccf8550fafde 100644 --- a/drivers/video/omap2/dss/display.c +++ b/drivers/video/omap2/dss/display.c | |||
@@ -142,7 +142,11 @@ static ssize_t display_timings_store(struct device *dev, | |||
142 | if (r) | 142 | if (r) |
143 | return r; | 143 | return r; |
144 | 144 | ||
145 | dssdev->driver->disable(dssdev); | ||
145 | dssdev->driver->set_timings(dssdev, &t); | 146 | dssdev->driver->set_timings(dssdev, &t); |
147 | r = dssdev->driver->enable(dssdev); | ||
148 | if (r) | ||
149 | return r; | ||
146 | 150 | ||
147 | return size; | 151 | return size; |
148 | } | 152 | } |
@@ -316,26 +320,117 @@ void omapdss_default_get_timings(struct omap_dss_device *dssdev, | |||
316 | } | 320 | } |
317 | EXPORT_SYMBOL(omapdss_default_get_timings); | 321 | EXPORT_SYMBOL(omapdss_default_get_timings); |
318 | 322 | ||
319 | void dss_init_device(struct platform_device *pdev, | 323 | /* |
324 | * Connect dssdev to a manager if the manager is free or if force is specified. | ||
325 | * Connect all overlays to that manager if they are free or if force is | ||
326 | * specified. | ||
327 | */ | ||
328 | static int dss_init_connections(struct omap_dss_device *dssdev, bool force) | ||
329 | { | ||
330 | struct omap_dss_output *out; | ||
331 | struct omap_overlay_manager *mgr; | ||
332 | int i, r; | ||
333 | |||
334 | out = omapdss_get_output_from_dssdev(dssdev); | ||
335 | |||
336 | WARN_ON(dssdev->output); | ||
337 | WARN_ON(out->device); | ||
338 | |||
339 | r = omapdss_output_set_device(out, dssdev); | ||
340 | if (r) { | ||
341 | DSSERR("failed to connect output to new device\n"); | ||
342 | return r; | ||
343 | } | ||
344 | |||
345 | mgr = omap_dss_get_overlay_manager(dssdev->channel); | ||
346 | |||
347 | if (mgr->output && !force) | ||
348 | return 0; | ||
349 | |||
350 | if (mgr->output) | ||
351 | mgr->unset_output(mgr); | ||
352 | |||
353 | r = mgr->set_output(mgr, out); | ||
354 | if (r) { | ||
355 | DSSERR("failed to connect manager to output of new device\n"); | ||
356 | |||
357 | /* remove the output-device connection we just made */ | ||
358 | omapdss_output_unset_device(out); | ||
359 | return r; | ||
360 | } | ||
361 | |||
362 | for (i = 0; i < omap_dss_get_num_overlays(); ++i) { | ||
363 | struct omap_overlay *ovl = omap_dss_get_overlay(i); | ||
364 | |||
365 | if (!ovl->manager || force) { | ||
366 | if (ovl->manager) | ||
367 | ovl->unset_manager(ovl); | ||
368 | |||
369 | r = ovl->set_manager(ovl, mgr); | ||
370 | if (r) { | ||
371 | DSSERR("failed to set initial overlay\n"); | ||
372 | return r; | ||
373 | } | ||
374 | } | ||
375 | } | ||
376 | |||
377 | return 0; | ||
378 | } | ||
379 | |||
380 | static void dss_uninit_connections(struct omap_dss_device *dssdev) | ||
381 | { | ||
382 | if (dssdev->output) { | ||
383 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
384 | |||
385 | if (mgr) | ||
386 | mgr->unset_output(mgr); | ||
387 | |||
388 | omapdss_output_unset_device(dssdev->output); | ||
389 | } | ||
390 | } | ||
391 | |||
392 | int dss_init_device(struct platform_device *pdev, | ||
320 | struct omap_dss_device *dssdev) | 393 | struct omap_dss_device *dssdev) |
321 | { | 394 | { |
322 | struct device_attribute *attr; | 395 | struct device_attribute *attr; |
323 | int i; | 396 | int i, r; |
324 | int r; | 397 | const char *def_disp_name = dss_get_default_display_name(); |
398 | bool force; | ||
399 | |||
400 | force = def_disp_name && strcmp(def_disp_name, dssdev->name) == 0; | ||
401 | dss_init_connections(dssdev, force); | ||
325 | 402 | ||
326 | /* create device sysfs files */ | 403 | /* create device sysfs files */ |
327 | i = 0; | 404 | i = 0; |
328 | while ((attr = display_sysfs_attrs[i++]) != NULL) { | 405 | while ((attr = display_sysfs_attrs[i++]) != NULL) { |
329 | r = device_create_file(&dssdev->dev, attr); | 406 | r = device_create_file(&dssdev->dev, attr); |
330 | if (r) | 407 | if (r) { |
408 | for (i = i - 2; i >= 0; i--) { | ||
409 | attr = display_sysfs_attrs[i]; | ||
410 | device_remove_file(&dssdev->dev, attr); | ||
411 | } | ||
412 | |||
413 | dss_uninit_connections(dssdev); | ||
414 | |||
331 | DSSERR("failed to create sysfs file\n"); | 415 | DSSERR("failed to create sysfs file\n"); |
416 | return r; | ||
417 | } | ||
332 | } | 418 | } |
333 | 419 | ||
334 | /* create display? sysfs links */ | 420 | /* create display? sysfs links */ |
335 | r = sysfs_create_link(&pdev->dev.kobj, &dssdev->dev.kobj, | 421 | r = sysfs_create_link(&pdev->dev.kobj, &dssdev->dev.kobj, |
336 | dev_name(&dssdev->dev)); | 422 | dev_name(&dssdev->dev)); |
337 | if (r) | 423 | if (r) { |
424 | while ((attr = display_sysfs_attrs[i++]) != NULL) | ||
425 | device_remove_file(&dssdev->dev, attr); | ||
426 | |||
427 | dss_uninit_connections(dssdev); | ||
428 | |||
338 | DSSERR("failed to create sysfs display link\n"); | 429 | DSSERR("failed to create sysfs display link\n"); |
430 | return r; | ||
431 | } | ||
432 | |||
433 | return 0; | ||
339 | } | 434 | } |
340 | 435 | ||
341 | void dss_uninit_device(struct platform_device *pdev, | 436 | void dss_uninit_device(struct platform_device *pdev, |
@@ -349,8 +444,7 @@ void dss_uninit_device(struct platform_device *pdev, | |||
349 | while ((attr = display_sysfs_attrs[i++]) != NULL) | 444 | while ((attr = display_sysfs_attrs[i++]) != NULL) |
350 | device_remove_file(&dssdev->dev, attr); | 445 | device_remove_file(&dssdev->dev, attr); |
351 | 446 | ||
352 | if (dssdev->manager) | 447 | dss_uninit_connections(dssdev); |
353 | dssdev->manager->unset_device(dssdev->manager); | ||
354 | } | 448 | } |
355 | 449 | ||
356 | static int dss_suspend_device(struct device *dev, void *data) | 450 | static int dss_suspend_device(struct device *dev, void *data) |
diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 3266be23fc0d..56748cf8760e 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c | |||
@@ -29,17 +29,24 @@ | |||
29 | #include <linux/errno.h> | 29 | #include <linux/errno.h> |
30 | #include <linux/platform_device.h> | 30 | #include <linux/platform_device.h> |
31 | #include <linux/regulator/consumer.h> | 31 | #include <linux/regulator/consumer.h> |
32 | #include <linux/string.h> | ||
32 | 33 | ||
33 | #include <video/omapdss.h> | 34 | #include <video/omapdss.h> |
34 | #include <plat/cpu.h> | ||
35 | 35 | ||
36 | #include "dss.h" | 36 | #include "dss.h" |
37 | #include "dss_features.h" | ||
37 | 38 | ||
38 | static struct { | 39 | static struct { |
39 | struct regulator *vdds_dsi_reg; | 40 | struct regulator *vdds_dsi_reg; |
40 | struct platform_device *dsidev; | 41 | struct platform_device *dsidev; |
41 | 42 | ||
43 | struct mutex lock; | ||
44 | |||
45 | struct omap_video_timings timings; | ||
42 | struct dss_lcd_mgr_config mgr_config; | 46 | struct dss_lcd_mgr_config mgr_config; |
47 | int data_lines; | ||
48 | |||
49 | struct omap_dss_output output; | ||
43 | } dpi; | 50 | } dpi; |
44 | 51 | ||
45 | static struct platform_device *dpi_get_dsidev(enum omap_dss_clk_source clk) | 52 | static struct platform_device *dpi_get_dsidev(enum omap_dss_clk_source clk) |
@@ -121,7 +128,8 @@ static int dpi_set_dispc_clk(struct omap_dss_device *dssdev, | |||
121 | 128 | ||
122 | static int dpi_set_mode(struct omap_dss_device *dssdev) | 129 | static int dpi_set_mode(struct omap_dss_device *dssdev) |
123 | { | 130 | { |
124 | struct omap_video_timings *t = &dssdev->panel.timings; | 131 | struct omap_video_timings *t = &dpi.timings; |
132 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
125 | int lck_div = 0, pck_div = 0; | 133 | int lck_div = 0, pck_div = 0; |
126 | unsigned long fck = 0; | 134 | unsigned long fck = 0; |
127 | unsigned long pck; | 135 | unsigned long pck; |
@@ -146,37 +154,44 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) | |||
146 | t->pixel_clock = pck; | 154 | t->pixel_clock = pck; |
147 | } | 155 | } |
148 | 156 | ||
149 | dss_mgr_set_timings(dssdev->manager, t); | 157 | dss_mgr_set_timings(mgr, t); |
150 | 158 | ||
151 | return 0; | 159 | return 0; |
152 | } | 160 | } |
153 | 161 | ||
154 | static void dpi_config_lcd_manager(struct omap_dss_device *dssdev) | 162 | static void dpi_config_lcd_manager(struct omap_dss_device *dssdev) |
155 | { | 163 | { |
164 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
165 | |||
156 | dpi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; | 166 | dpi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; |
157 | 167 | ||
158 | dpi.mgr_config.stallmode = false; | 168 | dpi.mgr_config.stallmode = false; |
159 | dpi.mgr_config.fifohandcheck = false; | 169 | dpi.mgr_config.fifohandcheck = false; |
160 | 170 | ||
161 | dpi.mgr_config.video_port_width = dssdev->phy.dpi.data_lines; | 171 | dpi.mgr_config.video_port_width = dpi.data_lines; |
162 | 172 | ||
163 | dpi.mgr_config.lcden_sig_polarity = 0; | 173 | dpi.mgr_config.lcden_sig_polarity = 0; |
164 | 174 | ||
165 | dss_mgr_set_lcd_config(dssdev->manager, &dpi.mgr_config); | 175 | dss_mgr_set_lcd_config(mgr, &dpi.mgr_config); |
166 | } | 176 | } |
167 | 177 | ||
168 | int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) | 178 | int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) |
169 | { | 179 | { |
180 | struct omap_dss_output *out = dssdev->output; | ||
170 | int r; | 181 | int r; |
171 | 182 | ||
172 | if (cpu_is_omap34xx() && !dpi.vdds_dsi_reg) { | 183 | mutex_lock(&dpi.lock); |
184 | |||
185 | if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && !dpi.vdds_dsi_reg) { | ||
173 | DSSERR("no VDSS_DSI regulator\n"); | 186 | DSSERR("no VDSS_DSI regulator\n"); |
174 | return -ENODEV; | 187 | r = -ENODEV; |
188 | goto err_no_reg; | ||
175 | } | 189 | } |
176 | 190 | ||
177 | if (dssdev->manager == NULL) { | 191 | if (out == NULL || out->manager == NULL) { |
178 | DSSERR("failed to enable display: no manager\n"); | 192 | DSSERR("failed to enable display: no output/manager\n"); |
179 | return -ENODEV; | 193 | r = -ENODEV; |
194 | goto err_no_out_mgr; | ||
180 | } | 195 | } |
181 | 196 | ||
182 | r = omap_dss_start_device(dssdev); | 197 | r = omap_dss_start_device(dssdev); |
@@ -185,7 +200,7 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) | |||
185 | goto err_start_dev; | 200 | goto err_start_dev; |
186 | } | 201 | } |
187 | 202 | ||
188 | if (cpu_is_omap34xx()) { | 203 | if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) { |
189 | r = regulator_enable(dpi.vdds_dsi_reg); | 204 | r = regulator_enable(dpi.vdds_dsi_reg); |
190 | if (r) | 205 | if (r) |
191 | goto err_reg_enable; | 206 | goto err_reg_enable; |
@@ -195,6 +210,10 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) | |||
195 | if (r) | 210 | if (r) |
196 | goto err_get_dispc; | 211 | goto err_get_dispc; |
197 | 212 | ||
213 | r = dss_dpi_select_source(dssdev->channel); | ||
214 | if (r) | ||
215 | goto err_src_sel; | ||
216 | |||
198 | if (dpi_use_dsi_pll(dssdev)) { | 217 | if (dpi_use_dsi_pll(dssdev)) { |
199 | r = dsi_runtime_get(dpi.dsidev); | 218 | r = dsi_runtime_get(dpi.dsidev); |
200 | if (r) | 219 | if (r) |
@@ -213,10 +232,12 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) | |||
213 | 232 | ||
214 | mdelay(2); | 233 | mdelay(2); |
215 | 234 | ||
216 | r = dss_mgr_enable(dssdev->manager); | 235 | r = dss_mgr_enable(out->manager); |
217 | if (r) | 236 | if (r) |
218 | goto err_mgr_enable; | 237 | goto err_mgr_enable; |
219 | 238 | ||
239 | mutex_unlock(&dpi.lock); | ||
240 | |||
220 | return 0; | 241 | return 0; |
221 | 242 | ||
222 | err_mgr_enable: | 243 | err_mgr_enable: |
@@ -227,20 +248,28 @@ err_dsi_pll_init: | |||
227 | if (dpi_use_dsi_pll(dssdev)) | 248 | if (dpi_use_dsi_pll(dssdev)) |
228 | dsi_runtime_put(dpi.dsidev); | 249 | dsi_runtime_put(dpi.dsidev); |
229 | err_get_dsi: | 250 | err_get_dsi: |
251 | err_src_sel: | ||
230 | dispc_runtime_put(); | 252 | dispc_runtime_put(); |
231 | err_get_dispc: | 253 | err_get_dispc: |
232 | if (cpu_is_omap34xx()) | 254 | if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) |
233 | regulator_disable(dpi.vdds_dsi_reg); | 255 | regulator_disable(dpi.vdds_dsi_reg); |
234 | err_reg_enable: | 256 | err_reg_enable: |
235 | omap_dss_stop_device(dssdev); | 257 | omap_dss_stop_device(dssdev); |
236 | err_start_dev: | 258 | err_start_dev: |
259 | err_no_out_mgr: | ||
260 | err_no_reg: | ||
261 | mutex_unlock(&dpi.lock); | ||
237 | return r; | 262 | return r; |
238 | } | 263 | } |
239 | EXPORT_SYMBOL(omapdss_dpi_display_enable); | 264 | EXPORT_SYMBOL(omapdss_dpi_display_enable); |
240 | 265 | ||
241 | void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) | 266 | void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) |
242 | { | 267 | { |
243 | dss_mgr_disable(dssdev->manager); | 268 | struct omap_overlay_manager *mgr = dssdev->output->manager; |
269 | |||
270 | mutex_lock(&dpi.lock); | ||
271 | |||
272 | dss_mgr_disable(mgr); | ||
244 | 273 | ||
245 | if (dpi_use_dsi_pll(dssdev)) { | 274 | if (dpi_use_dsi_pll(dssdev)) { |
246 | dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); | 275 | dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); |
@@ -250,44 +279,39 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) | |||
250 | 279 | ||
251 | dispc_runtime_put(); | 280 | dispc_runtime_put(); |
252 | 281 | ||
253 | if (cpu_is_omap34xx()) | 282 | if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) |
254 | regulator_disable(dpi.vdds_dsi_reg); | 283 | regulator_disable(dpi.vdds_dsi_reg); |
255 | 284 | ||
256 | omap_dss_stop_device(dssdev); | 285 | omap_dss_stop_device(dssdev); |
286 | |||
287 | mutex_unlock(&dpi.lock); | ||
257 | } | 288 | } |
258 | EXPORT_SYMBOL(omapdss_dpi_display_disable); | 289 | EXPORT_SYMBOL(omapdss_dpi_display_disable); |
259 | 290 | ||
260 | void dpi_set_timings(struct omap_dss_device *dssdev, | 291 | void omapdss_dpi_set_timings(struct omap_dss_device *dssdev, |
261 | struct omap_video_timings *timings) | 292 | struct omap_video_timings *timings) |
262 | { | 293 | { |
263 | int r; | ||
264 | |||
265 | DSSDBG("dpi_set_timings\n"); | 294 | DSSDBG("dpi_set_timings\n"); |
266 | dssdev->panel.timings = *timings; | ||
267 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { | ||
268 | r = dispc_runtime_get(); | ||
269 | if (r) | ||
270 | return; | ||
271 | 295 | ||
272 | dpi_set_mode(dssdev); | 296 | mutex_lock(&dpi.lock); |
273 | 297 | ||
274 | dispc_runtime_put(); | 298 | dpi.timings = *timings; |
275 | } else { | 299 | |
276 | dss_mgr_set_timings(dssdev->manager, timings); | 300 | mutex_unlock(&dpi.lock); |
277 | } | ||
278 | } | 301 | } |
279 | EXPORT_SYMBOL(dpi_set_timings); | 302 | EXPORT_SYMBOL(omapdss_dpi_set_timings); |
280 | 303 | ||
281 | int dpi_check_timings(struct omap_dss_device *dssdev, | 304 | int dpi_check_timings(struct omap_dss_device *dssdev, |
282 | struct omap_video_timings *timings) | 305 | struct omap_video_timings *timings) |
283 | { | 306 | { |
284 | int r; | 307 | int r; |
308 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
285 | int lck_div, pck_div; | 309 | int lck_div, pck_div; |
286 | unsigned long fck; | 310 | unsigned long fck; |
287 | unsigned long pck; | 311 | unsigned long pck; |
288 | struct dispc_clock_info dispc_cinfo; | 312 | struct dispc_clock_info dispc_cinfo; |
289 | 313 | ||
290 | if (dss_mgr_check_timings(dssdev->manager, timings)) | 314 | if (dss_mgr_check_timings(mgr, timings)) |
291 | return -EINVAL; | 315 | return -EINVAL; |
292 | 316 | ||
293 | if (timings->pixel_clock == 0) | 317 | if (timings->pixel_clock == 0) |
@@ -325,11 +349,22 @@ int dpi_check_timings(struct omap_dss_device *dssdev, | |||
325 | } | 349 | } |
326 | EXPORT_SYMBOL(dpi_check_timings); | 350 | EXPORT_SYMBOL(dpi_check_timings); |
327 | 351 | ||
352 | void omapdss_dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines) | ||
353 | { | ||
354 | mutex_lock(&dpi.lock); | ||
355 | |||
356 | dpi.data_lines = data_lines; | ||
357 | |||
358 | mutex_unlock(&dpi.lock); | ||
359 | } | ||
360 | EXPORT_SYMBOL(omapdss_dpi_set_data_lines); | ||
361 | |||
328 | static int __init dpi_init_display(struct omap_dss_device *dssdev) | 362 | static int __init dpi_init_display(struct omap_dss_device *dssdev) |
329 | { | 363 | { |
330 | DSSDBG("init_display\n"); | 364 | DSSDBG("init_display\n"); |
331 | 365 | ||
332 | if (cpu_is_omap34xx() && dpi.vdds_dsi_reg == NULL) { | 366 | if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && |
367 | dpi.vdds_dsi_reg == NULL) { | ||
333 | struct regulator *vdds_dsi; | 368 | struct regulator *vdds_dsi; |
334 | 369 | ||
335 | vdds_dsi = dss_get_vdds_dsi(); | 370 | vdds_dsi = dss_get_vdds_dsi(); |
@@ -351,10 +386,14 @@ static int __init dpi_init_display(struct omap_dss_device *dssdev) | |||
351 | return 0; | 386 | return 0; |
352 | } | 387 | } |
353 | 388 | ||
354 | static void __init dpi_probe_pdata(struct platform_device *pdev) | 389 | static struct omap_dss_device * __init dpi_find_dssdev(struct platform_device *pdev) |
355 | { | 390 | { |
356 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | 391 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; |
357 | int i, r; | 392 | const char *def_disp_name = dss_get_default_display_name(); |
393 | struct omap_dss_device *def_dssdev; | ||
394 | int i; | ||
395 | |||
396 | def_dssdev = NULL; | ||
358 | 397 | ||
359 | for (i = 0; i < pdata->num_devices; ++i) { | 398 | for (i = 0; i < pdata->num_devices; ++i) { |
360 | struct omap_dss_device *dssdev = pdata->devices[i]; | 399 | struct omap_dss_device *dssdev = pdata->devices[i]; |
@@ -362,21 +401,75 @@ static void __init dpi_probe_pdata(struct platform_device *pdev) | |||
362 | if (dssdev->type != OMAP_DISPLAY_TYPE_DPI) | 401 | if (dssdev->type != OMAP_DISPLAY_TYPE_DPI) |
363 | continue; | 402 | continue; |
364 | 403 | ||
365 | r = dpi_init_display(dssdev); | 404 | if (def_dssdev == NULL) |
366 | if (r) { | 405 | def_dssdev = dssdev; |
367 | DSSERR("device %s init failed: %d\n", dssdev->name, r); | 406 | |
368 | continue; | 407 | if (def_disp_name != NULL && |
408 | strcmp(dssdev->name, def_disp_name) == 0) { | ||
409 | def_dssdev = dssdev; | ||
410 | break; | ||
369 | } | 411 | } |
412 | } | ||
370 | 413 | ||
371 | r = omap_dss_register_device(dssdev, &pdev->dev, i); | 414 | return def_dssdev; |
372 | if (r) | 415 | } |
373 | DSSERR("device %s register failed: %d\n", | 416 | |
374 | dssdev->name, r); | 417 | static void __init dpi_probe_pdata(struct platform_device *dpidev) |
418 | { | ||
419 | struct omap_dss_device *plat_dssdev; | ||
420 | struct omap_dss_device *dssdev; | ||
421 | int r; | ||
422 | |||
423 | plat_dssdev = dpi_find_dssdev(dpidev); | ||
424 | |||
425 | if (!plat_dssdev) | ||
426 | return; | ||
427 | |||
428 | dssdev = dss_alloc_and_init_device(&dpidev->dev); | ||
429 | if (!dssdev) | ||
430 | return; | ||
431 | |||
432 | dss_copy_device_pdata(dssdev, plat_dssdev); | ||
433 | |||
434 | r = dpi_init_display(dssdev); | ||
435 | if (r) { | ||
436 | DSSERR("device %s init failed: %d\n", dssdev->name, r); | ||
437 | dss_put_device(dssdev); | ||
438 | return; | ||
439 | } | ||
440 | |||
441 | r = dss_add_device(dssdev); | ||
442 | if (r) { | ||
443 | DSSERR("device %s register failed: %d\n", dssdev->name, r); | ||
444 | dss_put_device(dssdev); | ||
445 | return; | ||
375 | } | 446 | } |
376 | } | 447 | } |
377 | 448 | ||
449 | static void __init dpi_init_output(struct platform_device *pdev) | ||
450 | { | ||
451 | struct omap_dss_output *out = &dpi.output; | ||
452 | |||
453 | out->pdev = pdev; | ||
454 | out->id = OMAP_DSS_OUTPUT_DPI; | ||
455 | out->type = OMAP_DISPLAY_TYPE_DPI; | ||
456 | |||
457 | dss_register_output(out); | ||
458 | } | ||
459 | |||
460 | static void __exit dpi_uninit_output(struct platform_device *pdev) | ||
461 | { | ||
462 | struct omap_dss_output *out = &dpi.output; | ||
463 | |||
464 | dss_unregister_output(out); | ||
465 | } | ||
466 | |||
378 | static int __init omap_dpi_probe(struct platform_device *pdev) | 467 | static int __init omap_dpi_probe(struct platform_device *pdev) |
379 | { | 468 | { |
469 | mutex_init(&dpi.lock); | ||
470 | |||
471 | dpi_init_output(pdev); | ||
472 | |||
380 | dpi_probe_pdata(pdev); | 473 | dpi_probe_pdata(pdev); |
381 | 474 | ||
382 | return 0; | 475 | return 0; |
@@ -384,7 +477,9 @@ static int __init omap_dpi_probe(struct platform_device *pdev) | |||
384 | 477 | ||
385 | static int __exit omap_dpi_remove(struct platform_device *pdev) | 478 | static int __exit omap_dpi_remove(struct platform_device *pdev) |
386 | { | 479 | { |
387 | omap_dss_unregister_child_devices(&pdev->dev); | 480 | dss_unregister_child_devices(&pdev->dev); |
481 | |||
482 | dpi_uninit_output(pdev); | ||
388 | 483 | ||
389 | return 0; | 484 | return 0; |
390 | } | 485 | } |
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 05ee04667af1..d64ac3842884 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c | |||
@@ -41,7 +41,6 @@ | |||
41 | 41 | ||
42 | #include <video/omapdss.h> | 42 | #include <video/omapdss.h> |
43 | #include <video/mipi_display.h> | 43 | #include <video/mipi_display.h> |
44 | #include <plat/clock.h> | ||
45 | 44 | ||
46 | #include "dss.h" | 45 | #include "dss.h" |
47 | #include "dss_features.h" | 46 | #include "dss_features.h" |
@@ -333,6 +332,12 @@ struct dsi_data { | |||
333 | unsigned scp_clk_refcount; | 332 | unsigned scp_clk_refcount; |
334 | 333 | ||
335 | struct dss_lcd_mgr_config mgr_config; | 334 | struct dss_lcd_mgr_config mgr_config; |
335 | struct omap_video_timings timings; | ||
336 | enum omap_dss_dsi_pixel_format pix_fmt; | ||
337 | enum omap_dss_dsi_mode mode; | ||
338 | struct omap_dss_dsi_videomode_timings vm_timings; | ||
339 | |||
340 | struct omap_dss_output output; | ||
336 | }; | 341 | }; |
337 | 342 | ||
338 | struct dsi_packet_sent_handler_data { | 343 | struct dsi_packet_sent_handler_data { |
@@ -340,8 +345,6 @@ struct dsi_packet_sent_handler_data { | |||
340 | struct completion *completion; | 345 | struct completion *completion; |
341 | }; | 346 | }; |
342 | 347 | ||
343 | static struct platform_device *dsi_pdev_map[MAX_NUM_DSI]; | ||
344 | |||
345 | #ifdef DEBUG | 348 | #ifdef DEBUG |
346 | static bool dsi_perf; | 349 | static bool dsi_perf; |
347 | module_param(dsi_perf, bool, 0644); | 350 | module_param(dsi_perf, bool, 0644); |
@@ -354,12 +357,19 @@ static inline struct dsi_data *dsi_get_dsidrv_data(struct platform_device *dside | |||
354 | 357 | ||
355 | static inline struct platform_device *dsi_get_dsidev_from_dssdev(struct omap_dss_device *dssdev) | 358 | static inline struct platform_device *dsi_get_dsidev_from_dssdev(struct omap_dss_device *dssdev) |
356 | { | 359 | { |
357 | return dsi_pdev_map[dssdev->phy.dsi.module]; | 360 | return dssdev->output->pdev; |
358 | } | 361 | } |
359 | 362 | ||
360 | struct platform_device *dsi_get_dsidev_from_id(int module) | 363 | struct platform_device *dsi_get_dsidev_from_id(int module) |
361 | { | 364 | { |
362 | return dsi_pdev_map[module]; | 365 | struct omap_dss_output *out; |
366 | enum omap_dss_output_id id; | ||
367 | |||
368 | id = module == 0 ? OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2; | ||
369 | |||
370 | out = omap_dss_get_output(id); | ||
371 | |||
372 | return out->pdev; | ||
363 | } | 373 | } |
364 | 374 | ||
365 | static inline void dsi_write_reg(struct platform_device *dsidev, | 375 | static inline void dsi_write_reg(struct platform_device *dsidev, |
@@ -1450,6 +1460,148 @@ found: | |||
1450 | return 0; | 1460 | return 0; |
1451 | } | 1461 | } |
1452 | 1462 | ||
1463 | static int dsi_pll_calc_ddrfreq(struct platform_device *dsidev, | ||
1464 | unsigned long req_clkin4ddr, struct dsi_clock_info *cinfo) | ||
1465 | { | ||
1466 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
1467 | struct dsi_clock_info cur, best; | ||
1468 | |||
1469 | DSSDBG("dsi_pll_calc_ddrfreq\n"); | ||
1470 | |||
1471 | memset(&best, 0, sizeof(best)); | ||
1472 | memset(&cur, 0, sizeof(cur)); | ||
1473 | |||
1474 | cur.clkin = clk_get_rate(dsi->sys_clk); | ||
1475 | |||
1476 | for (cur.regn = 1; cur.regn < dsi->regn_max; ++cur.regn) { | ||
1477 | cur.fint = cur.clkin / cur.regn; | ||
1478 | |||
1479 | if (cur.fint > dsi->fint_max || cur.fint < dsi->fint_min) | ||
1480 | continue; | ||
1481 | |||
1482 | /* DSIPHY(MHz) = (2 * regm / regn) * clkin */ | ||
1483 | for (cur.regm = 1; cur.regm < dsi->regm_max; ++cur.regm) { | ||
1484 | unsigned long a, b; | ||
1485 | |||
1486 | a = 2 * cur.regm * (cur.clkin/1000); | ||
1487 | b = cur.regn; | ||
1488 | cur.clkin4ddr = a / b * 1000; | ||
1489 | |||
1490 | if (cur.clkin4ddr > 1800 * 1000 * 1000) | ||
1491 | break; | ||
1492 | |||
1493 | if (abs(cur.clkin4ddr - req_clkin4ddr) < | ||
1494 | abs(best.clkin4ddr - req_clkin4ddr)) { | ||
1495 | best = cur; | ||
1496 | DSSDBG("best %ld\n", best.clkin4ddr); | ||
1497 | } | ||
1498 | |||
1499 | if (cur.clkin4ddr == req_clkin4ddr) | ||
1500 | goto found; | ||
1501 | } | ||
1502 | } | ||
1503 | found: | ||
1504 | if (cinfo) | ||
1505 | *cinfo = best; | ||
1506 | |||
1507 | return 0; | ||
1508 | } | ||
1509 | |||
1510 | static void dsi_pll_calc_dsi_fck(struct platform_device *dsidev, | ||
1511 | struct dsi_clock_info *cinfo) | ||
1512 | { | ||
1513 | unsigned long max_dsi_fck; | ||
1514 | |||
1515 | max_dsi_fck = dss_feat_get_param_max(FEAT_PARAM_DSI_FCK); | ||
1516 | |||
1517 | cinfo->regm_dsi = DIV_ROUND_UP(cinfo->clkin4ddr, max_dsi_fck); | ||
1518 | cinfo->dsi_pll_hsdiv_dsi_clk = cinfo->clkin4ddr / cinfo->regm_dsi; | ||
1519 | } | ||
1520 | |||
1521 | static int dsi_pll_calc_dispc_fck(struct platform_device *dsidev, | ||
1522 | unsigned long req_pck, struct dsi_clock_info *cinfo, | ||
1523 | struct dispc_clock_info *dispc_cinfo) | ||
1524 | { | ||
1525 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
1526 | unsigned regm_dispc, best_regm_dispc; | ||
1527 | unsigned long dispc_clk, best_dispc_clk; | ||
1528 | int min_fck_per_pck; | ||
1529 | unsigned long max_dss_fck; | ||
1530 | struct dispc_clock_info best_dispc; | ||
1531 | bool match; | ||
1532 | |||
1533 | max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); | ||
1534 | |||
1535 | min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK; | ||
1536 | |||
1537 | if (min_fck_per_pck && | ||
1538 | req_pck * min_fck_per_pck > max_dss_fck) { | ||
1539 | DSSERR("Requested pixel clock not possible with the current " | ||
1540 | "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning " | ||
1541 | "the constraint off.\n"); | ||
1542 | min_fck_per_pck = 0; | ||
1543 | } | ||
1544 | |||
1545 | retry: | ||
1546 | best_regm_dispc = 0; | ||
1547 | best_dispc_clk = 0; | ||
1548 | memset(&best_dispc, 0, sizeof(best_dispc)); | ||
1549 | match = false; | ||
1550 | |||
1551 | for (regm_dispc = 1; regm_dispc < dsi->regm_dispc_max; ++regm_dispc) { | ||
1552 | struct dispc_clock_info cur_dispc; | ||
1553 | |||
1554 | dispc_clk = cinfo->clkin4ddr / regm_dispc; | ||
1555 | |||
1556 | /* this will narrow down the search a bit, | ||
1557 | * but still give pixclocks below what was | ||
1558 | * requested */ | ||
1559 | if (dispc_clk < req_pck) | ||
1560 | break; | ||
1561 | |||
1562 | if (dispc_clk > max_dss_fck) | ||
1563 | continue; | ||
1564 | |||
1565 | if (min_fck_per_pck && dispc_clk < req_pck * min_fck_per_pck) | ||
1566 | continue; | ||
1567 | |||
1568 | match = true; | ||
1569 | |||
1570 | dispc_find_clk_divs(req_pck, dispc_clk, &cur_dispc); | ||
1571 | |||
1572 | if (abs(cur_dispc.pck - req_pck) < | ||
1573 | abs(best_dispc.pck - req_pck)) { | ||
1574 | best_regm_dispc = regm_dispc; | ||
1575 | best_dispc_clk = dispc_clk; | ||
1576 | best_dispc = cur_dispc; | ||
1577 | |||
1578 | if (cur_dispc.pck == req_pck) | ||
1579 | goto found; | ||
1580 | } | ||
1581 | } | ||
1582 | |||
1583 | if (!match) { | ||
1584 | if (min_fck_per_pck) { | ||
1585 | DSSERR("Could not find suitable clock settings.\n" | ||
1586 | "Turning FCK/PCK constraint off and" | ||
1587 | "trying again.\n"); | ||
1588 | min_fck_per_pck = 0; | ||
1589 | goto retry; | ||
1590 | } | ||
1591 | |||
1592 | DSSERR("Could not find suitable clock settings.\n"); | ||
1593 | |||
1594 | return -EINVAL; | ||
1595 | } | ||
1596 | found: | ||
1597 | cinfo->regm_dispc = best_regm_dispc; | ||
1598 | cinfo->dsi_pll_hsdiv_dispc_clk = best_dispc_clk; | ||
1599 | |||
1600 | *dispc_cinfo = best_dispc; | ||
1601 | |||
1602 | return 0; | ||
1603 | } | ||
1604 | |||
1453 | int dsi_pll_set_clock_div(struct platform_device *dsidev, | 1605 | int dsi_pll_set_clock_div(struct platform_device *dsidev, |
1454 | struct dsi_clock_info *cinfo) | 1606 | struct dsi_clock_info *cinfo) |
1455 | { | 1607 | { |
@@ -1526,21 +1678,27 @@ int dsi_pll_set_clock_div(struct platform_device *dsidev, | |||
1526 | 1678 | ||
1527 | BUG_ON(cinfo->fint < dsi->fint_min || cinfo->fint > dsi->fint_max); | 1679 | BUG_ON(cinfo->fint < dsi->fint_min || cinfo->fint > dsi->fint_max); |
1528 | 1680 | ||
1681 | l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2); | ||
1682 | |||
1529 | if (dss_has_feature(FEAT_DSI_PLL_FREQSEL)) { | 1683 | if (dss_has_feature(FEAT_DSI_PLL_FREQSEL)) { |
1530 | f = cinfo->fint < 1000000 ? 0x3 : | 1684 | f = cinfo->fint < 1000000 ? 0x3 : |
1531 | cinfo->fint < 1250000 ? 0x4 : | 1685 | cinfo->fint < 1250000 ? 0x4 : |
1532 | cinfo->fint < 1500000 ? 0x5 : | 1686 | cinfo->fint < 1500000 ? 0x5 : |
1533 | cinfo->fint < 1750000 ? 0x6 : | 1687 | cinfo->fint < 1750000 ? 0x6 : |
1534 | 0x7; | 1688 | 0x7; |
1535 | } | ||
1536 | 1689 | ||
1537 | l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2); | ||
1538 | |||
1539 | if (dss_has_feature(FEAT_DSI_PLL_FREQSEL)) | ||
1540 | l = FLD_MOD(l, f, 4, 1); /* DSI_PLL_FREQSEL */ | 1690 | l = FLD_MOD(l, f, 4, 1); /* DSI_PLL_FREQSEL */ |
1691 | } else if (dss_has_feature(FEAT_DSI_PLL_SELFREQDCO)) { | ||
1692 | f = cinfo->clkin4ddr < 1000000000 ? 0x2 : 0x4; | ||
1693 | |||
1694 | l = FLD_MOD(l, f, 4, 1); /* PLL_SELFREQDCO */ | ||
1695 | } | ||
1696 | |||
1541 | l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */ | 1697 | l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */ |
1542 | l = FLD_MOD(l, 0, 14, 14); /* DSIPHY_CLKINEN */ | 1698 | l = FLD_MOD(l, 0, 14, 14); /* DSIPHY_CLKINEN */ |
1543 | l = FLD_MOD(l, 1, 20, 20); /* DSI_HSDIVBYPASS */ | 1699 | l = FLD_MOD(l, 1, 20, 20); /* DSI_HSDIVBYPASS */ |
1700 | if (dss_has_feature(FEAT_DSI_PLL_REFSEL)) | ||
1701 | l = FLD_MOD(l, 3, 22, 21); /* REF_SYSCLK = sysclk */ | ||
1544 | dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION2, l); | 1702 | dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION2, l); |
1545 | 1703 | ||
1546 | REG_FLD_MOD(dsidev, DSI_PLL_GO, 1, 0, 0); /* DSI_PLL_GO */ | 1704 | REG_FLD_MOD(dsidev, DSI_PLL_GO, 1, 0, 0); /* DSI_PLL_GO */ |
@@ -2004,15 +2162,16 @@ static unsigned dsi_get_line_buf_size(struct platform_device *dsidev) | |||
2004 | return 1194 * 3; /* 1194x24 bits */ | 2162 | return 1194 * 3; /* 1194x24 bits */ |
2005 | case 6: | 2163 | case 6: |
2006 | return 1365 * 3; /* 1365x24 bits */ | 2164 | return 1365 * 3; /* 1365x24 bits */ |
2165 | case 7: | ||
2166 | return 1920 * 3; /* 1920x24 bits */ | ||
2007 | default: | 2167 | default: |
2008 | BUG(); | 2168 | BUG(); |
2009 | return 0; | 2169 | return 0; |
2010 | } | 2170 | } |
2011 | } | 2171 | } |
2012 | 2172 | ||
2013 | static int dsi_set_lane_config(struct omap_dss_device *dssdev) | 2173 | static int dsi_set_lane_config(struct platform_device *dsidev) |
2014 | { | 2174 | { |
2015 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
2016 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 2175 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
2017 | static const u8 offsets[] = { 0, 4, 8, 12, 16 }; | 2176 | static const u8 offsets[] = { 0, 4, 8, 12, 16 }; |
2018 | static const enum dsi_lane_function functions[] = { | 2177 | static const enum dsi_lane_function functions[] = { |
@@ -2136,9 +2295,16 @@ static void dsi_cio_timings(struct platform_device *dsidev) | |||
2136 | dsi_write_reg(dsidev, DSI_DSIPHY_CFG0, r); | 2295 | dsi_write_reg(dsidev, DSI_DSIPHY_CFG0, r); |
2137 | 2296 | ||
2138 | r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1); | 2297 | r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1); |
2139 | r = FLD_MOD(r, tlpx_half, 22, 16); | 2298 | r = FLD_MOD(r, tlpx_half, 20, 16); |
2140 | r = FLD_MOD(r, tclk_trail, 15, 8); | 2299 | r = FLD_MOD(r, tclk_trail, 15, 8); |
2141 | r = FLD_MOD(r, tclk_zero, 7, 0); | 2300 | r = FLD_MOD(r, tclk_zero, 7, 0); |
2301 | |||
2302 | if (dss_has_feature(FEAT_DSI_PHY_DCC)) { | ||
2303 | r = FLD_MOD(r, 0, 21, 21); /* DCCEN = disable */ | ||
2304 | r = FLD_MOD(r, 1, 22, 22); /* CLKINP_DIVBY2EN = enable */ | ||
2305 | r = FLD_MOD(r, 1, 23, 23); /* CLKINP_SEL = enable */ | ||
2306 | } | ||
2307 | |||
2142 | dsi_write_reg(dsidev, DSI_DSIPHY_CFG1, r); | 2308 | dsi_write_reg(dsidev, DSI_DSIPHY_CFG1, r); |
2143 | 2309 | ||
2144 | r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2); | 2310 | r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2); |
@@ -2147,10 +2313,9 @@ static void dsi_cio_timings(struct platform_device *dsidev) | |||
2147 | } | 2313 | } |
2148 | 2314 | ||
2149 | /* lane masks have lane 0 at lsb. mask_p for positive lines, n for negative */ | 2315 | /* lane masks have lane 0 at lsb. mask_p for positive lines, n for negative */ |
2150 | static void dsi_cio_enable_lane_override(struct omap_dss_device *dssdev, | 2316 | static void dsi_cio_enable_lane_override(struct platform_device *dsidev, |
2151 | unsigned mask_p, unsigned mask_n) | 2317 | unsigned mask_p, unsigned mask_n) |
2152 | { | 2318 | { |
2153 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
2154 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 2319 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
2155 | int i; | 2320 | int i; |
2156 | u32 l; | 2321 | u32 l; |
@@ -2197,9 +2362,8 @@ static void dsi_cio_disable_lane_override(struct platform_device *dsidev) | |||
2197 | REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 0, 22, 17); | 2362 | REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 0, 22, 17); |
2198 | } | 2363 | } |
2199 | 2364 | ||
2200 | static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev) | 2365 | static int dsi_cio_wait_tx_clk_esc_reset(struct platform_device *dsidev) |
2201 | { | 2366 | { |
2202 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
2203 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 2367 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
2204 | int t, i; | 2368 | int t, i; |
2205 | bool in_use[DSI_MAX_NR_LANES]; | 2369 | bool in_use[DSI_MAX_NR_LANES]; |
@@ -2247,9 +2411,8 @@ static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev) | |||
2247 | } | 2411 | } |
2248 | 2412 | ||
2249 | /* return bitmask of enabled lanes, lane0 being the lsb */ | 2413 | /* return bitmask of enabled lanes, lane0 being the lsb */ |
2250 | static unsigned dsi_get_lane_mask(struct omap_dss_device *dssdev) | 2414 | static unsigned dsi_get_lane_mask(struct platform_device *dsidev) |
2251 | { | 2415 | { |
2252 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
2253 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 2416 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
2254 | unsigned mask = 0; | 2417 | unsigned mask = 0; |
2255 | int i; | 2418 | int i; |
@@ -2262,16 +2425,15 @@ static unsigned dsi_get_lane_mask(struct omap_dss_device *dssdev) | |||
2262 | return mask; | 2425 | return mask; |
2263 | } | 2426 | } |
2264 | 2427 | ||
2265 | static int dsi_cio_init(struct omap_dss_device *dssdev) | 2428 | static int dsi_cio_init(struct platform_device *dsidev) |
2266 | { | 2429 | { |
2267 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
2268 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 2430 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
2269 | int r; | 2431 | int r; |
2270 | u32 l; | 2432 | u32 l; |
2271 | 2433 | ||
2272 | DSSDBGF(); | 2434 | DSSDBGF(); |
2273 | 2435 | ||
2274 | r = dss_dsi_enable_pads(dsi->module_id, dsi_get_lane_mask(dssdev)); | 2436 | r = dss_dsi_enable_pads(dsi->module_id, dsi_get_lane_mask(dsidev)); |
2275 | if (r) | 2437 | if (r) |
2276 | return r; | 2438 | return r; |
2277 | 2439 | ||
@@ -2288,7 +2450,7 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) | |||
2288 | goto err_scp_clk_dom; | 2450 | goto err_scp_clk_dom; |
2289 | } | 2451 | } |
2290 | 2452 | ||
2291 | r = dsi_set_lane_config(dssdev); | 2453 | r = dsi_set_lane_config(dsidev); |
2292 | if (r) | 2454 | if (r) |
2293 | goto err_scp_clk_dom; | 2455 | goto err_scp_clk_dom; |
2294 | 2456 | ||
@@ -2323,7 +2485,7 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) | |||
2323 | mask_p |= 1 << i; | 2485 | mask_p |= 1 << i; |
2324 | } | 2486 | } |
2325 | 2487 | ||
2326 | dsi_cio_enable_lane_override(dssdev, mask_p, 0); | 2488 | dsi_cio_enable_lane_override(dsidev, mask_p, 0); |
2327 | } | 2489 | } |
2328 | 2490 | ||
2329 | r = dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ON); | 2491 | r = dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ON); |
@@ -2340,7 +2502,7 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) | |||
2340 | dsi_if_enable(dsidev, false); | 2502 | dsi_if_enable(dsidev, false); |
2341 | REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */ | 2503 | REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */ |
2342 | 2504 | ||
2343 | r = dsi_cio_wait_tx_clk_esc_reset(dssdev); | 2505 | r = dsi_cio_wait_tx_clk_esc_reset(dsidev); |
2344 | if (r) | 2506 | if (r) |
2345 | goto err_tx_clk_esc_rst; | 2507 | goto err_tx_clk_esc_rst; |
2346 | 2508 | ||
@@ -2360,10 +2522,10 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) | |||
2360 | 2522 | ||
2361 | dsi_cio_timings(dsidev); | 2523 | dsi_cio_timings(dsidev); |
2362 | 2524 | ||
2363 | if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { | 2525 | if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { |
2364 | /* DDR_CLK_ALWAYS_ON */ | 2526 | /* DDR_CLK_ALWAYS_ON */ |
2365 | REG_FLD_MOD(dsidev, DSI_CLK_CTRL, | 2527 | REG_FLD_MOD(dsidev, DSI_CLK_CTRL, |
2366 | dssdev->panel.dsi_vm_data.ddr_clk_always_on, 13, 13); | 2528 | dsi->vm_timings.ddr_clk_always_on, 13, 13); |
2367 | } | 2529 | } |
2368 | 2530 | ||
2369 | dsi->ulps_enabled = false; | 2531 | dsi->ulps_enabled = false; |
@@ -2381,13 +2543,12 @@ err_cio_pwr: | |||
2381 | dsi_cio_disable_lane_override(dsidev); | 2543 | dsi_cio_disable_lane_override(dsidev); |
2382 | err_scp_clk_dom: | 2544 | err_scp_clk_dom: |
2383 | dsi_disable_scp_clk(dsidev); | 2545 | dsi_disable_scp_clk(dsidev); |
2384 | dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dssdev)); | 2546 | dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dsidev)); |
2385 | return r; | 2547 | return r; |
2386 | } | 2548 | } |
2387 | 2549 | ||
2388 | static void dsi_cio_uninit(struct omap_dss_device *dssdev) | 2550 | static void dsi_cio_uninit(struct platform_device *dsidev) |
2389 | { | 2551 | { |
2390 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
2391 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 2552 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
2392 | 2553 | ||
2393 | /* DDR_CLK_ALWAYS_ON */ | 2554 | /* DDR_CLK_ALWAYS_ON */ |
@@ -2395,7 +2556,7 @@ static void dsi_cio_uninit(struct omap_dss_device *dssdev) | |||
2395 | 2556 | ||
2396 | dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF); | 2557 | dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF); |
2397 | dsi_disable_scp_clk(dsidev); | 2558 | dsi_disable_scp_clk(dsidev); |
2398 | dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dssdev)); | 2559 | dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dsidev)); |
2399 | } | 2560 | } |
2400 | 2561 | ||
2401 | static void dsi_config_tx_fifo(struct platform_device *dsidev, | 2562 | static void dsi_config_tx_fifo(struct platform_device *dsidev, |
@@ -2685,6 +2846,7 @@ void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel, | |||
2685 | bool enable) | 2846 | bool enable) |
2686 | { | 2847 | { |
2687 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 2848 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
2849 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
2688 | 2850 | ||
2689 | DSSDBG("dsi_vc_enable_hs(%d, %d)\n", channel, enable); | 2851 | DSSDBG("dsi_vc_enable_hs(%d, %d)\n", channel, enable); |
2690 | 2852 | ||
@@ -2701,7 +2863,7 @@ void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel, | |||
2701 | dsi_force_tx_stop_mode_io(dsidev); | 2863 | dsi_force_tx_stop_mode_io(dsidev); |
2702 | 2864 | ||
2703 | /* start the DDR clock by sending a NULL packet */ | 2865 | /* start the DDR clock by sending a NULL packet */ |
2704 | if (dssdev->panel.dsi_vm_data.ddr_clk_always_on && enable) | 2866 | if (dsi->vm_timings.ddr_clk_always_on && enable) |
2705 | dsi_vc_send_null(dssdev, channel); | 2867 | dsi_vc_send_null(dssdev, channel); |
2706 | } | 2868 | } |
2707 | EXPORT_SYMBOL(omapdss_dsi_vc_enable_hs); | 2869 | EXPORT_SYMBOL(omapdss_dsi_vc_enable_hs); |
@@ -2987,10 +3149,9 @@ int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel) | |||
2987 | } | 3149 | } |
2988 | EXPORT_SYMBOL(dsi_vc_send_null); | 3150 | EXPORT_SYMBOL(dsi_vc_send_null); |
2989 | 3151 | ||
2990 | static int dsi_vc_write_nosync_common(struct omap_dss_device *dssdev, | 3152 | static int dsi_vc_write_nosync_common(struct platform_device *dsidev, |
2991 | int channel, u8 *data, int len, enum dss_dsi_content_type type) | 3153 | int channel, u8 *data, int len, enum dss_dsi_content_type type) |
2992 | { | 3154 | { |
2993 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
2994 | int r; | 3155 | int r; |
2995 | 3156 | ||
2996 | if (len == 0) { | 3157 | if (len == 0) { |
@@ -3021,7 +3182,9 @@ static int dsi_vc_write_nosync_common(struct omap_dss_device *dssdev, | |||
3021 | int dsi_vc_dcs_write_nosync(struct omap_dss_device *dssdev, int channel, | 3182 | int dsi_vc_dcs_write_nosync(struct omap_dss_device *dssdev, int channel, |
3022 | u8 *data, int len) | 3183 | u8 *data, int len) |
3023 | { | 3184 | { |
3024 | return dsi_vc_write_nosync_common(dssdev, channel, data, len, | 3185 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
3186 | |||
3187 | return dsi_vc_write_nosync_common(dsidev, channel, data, len, | ||
3025 | DSS_DSI_CONTENT_DCS); | 3188 | DSS_DSI_CONTENT_DCS); |
3026 | } | 3189 | } |
3027 | EXPORT_SYMBOL(dsi_vc_dcs_write_nosync); | 3190 | EXPORT_SYMBOL(dsi_vc_dcs_write_nosync); |
@@ -3029,7 +3192,9 @@ EXPORT_SYMBOL(dsi_vc_dcs_write_nosync); | |||
3029 | int dsi_vc_generic_write_nosync(struct omap_dss_device *dssdev, int channel, | 3192 | int dsi_vc_generic_write_nosync(struct omap_dss_device *dssdev, int channel, |
3030 | u8 *data, int len) | 3193 | u8 *data, int len) |
3031 | { | 3194 | { |
3032 | return dsi_vc_write_nosync_common(dssdev, channel, data, len, | 3195 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
3196 | |||
3197 | return dsi_vc_write_nosync_common(dsidev, channel, data, len, | ||
3033 | DSS_DSI_CONTENT_GENERIC); | 3198 | DSS_DSI_CONTENT_GENERIC); |
3034 | } | 3199 | } |
3035 | EXPORT_SYMBOL(dsi_vc_generic_write_nosync); | 3200 | EXPORT_SYMBOL(dsi_vc_generic_write_nosync); |
@@ -3040,7 +3205,7 @@ static int dsi_vc_write_common(struct omap_dss_device *dssdev, int channel, | |||
3040 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 3205 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
3041 | int r; | 3206 | int r; |
3042 | 3207 | ||
3043 | r = dsi_vc_write_nosync_common(dssdev, channel, data, len, type); | 3208 | r = dsi_vc_write_nosync_common(dsidev, channel, data, len, type); |
3044 | if (r) | 3209 | if (r) |
3045 | goto err; | 3210 | goto err; |
3046 | 3211 | ||
@@ -3118,10 +3283,9 @@ int dsi_vc_generic_write_2(struct omap_dss_device *dssdev, int channel, | |||
3118 | } | 3283 | } |
3119 | EXPORT_SYMBOL(dsi_vc_generic_write_2); | 3284 | EXPORT_SYMBOL(dsi_vc_generic_write_2); |
3120 | 3285 | ||
3121 | static int dsi_vc_dcs_send_read_request(struct omap_dss_device *dssdev, | 3286 | static int dsi_vc_dcs_send_read_request(struct platform_device *dsidev, |
3122 | int channel, u8 dcs_cmd) | 3287 | int channel, u8 dcs_cmd) |
3123 | { | 3288 | { |
3124 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
3125 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 3289 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
3126 | int r; | 3290 | int r; |
3127 | 3291 | ||
@@ -3139,10 +3303,9 @@ static int dsi_vc_dcs_send_read_request(struct omap_dss_device *dssdev, | |||
3139 | return 0; | 3303 | return 0; |
3140 | } | 3304 | } |
3141 | 3305 | ||
3142 | static int dsi_vc_generic_send_read_request(struct omap_dss_device *dssdev, | 3306 | static int dsi_vc_generic_send_read_request(struct platform_device *dsidev, |
3143 | int channel, u8 *reqdata, int reqlen) | 3307 | int channel, u8 *reqdata, int reqlen) |
3144 | { | 3308 | { |
3145 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
3146 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 3309 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
3147 | u16 data; | 3310 | u16 data; |
3148 | u8 data_type; | 3311 | u8 data_type; |
@@ -3291,7 +3454,7 @@ int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd, | |||
3291 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 3454 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
3292 | int r; | 3455 | int r; |
3293 | 3456 | ||
3294 | r = dsi_vc_dcs_send_read_request(dssdev, channel, dcs_cmd); | 3457 | r = dsi_vc_dcs_send_read_request(dsidev, channel, dcs_cmd); |
3295 | if (r) | 3458 | if (r) |
3296 | goto err; | 3459 | goto err; |
3297 | 3460 | ||
@@ -3322,7 +3485,7 @@ static int dsi_vc_generic_read(struct omap_dss_device *dssdev, int channel, | |||
3322 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 3485 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
3323 | int r; | 3486 | int r; |
3324 | 3487 | ||
3325 | r = dsi_vc_generic_send_read_request(dssdev, channel, reqdata, reqlen); | 3488 | r = dsi_vc_generic_send_read_request(dsidev, channel, reqdata, reqlen); |
3326 | if (r) | 3489 | if (r) |
3327 | return r; | 3490 | return r; |
3328 | 3491 | ||
@@ -3604,15 +3767,15 @@ static void dsi_set_hs_tx_timeout(struct platform_device *dsidev, | |||
3604 | (total_ticks * 1000) / (fck / 1000 / 1000)); | 3767 | (total_ticks * 1000) / (fck / 1000 / 1000)); |
3605 | } | 3768 | } |
3606 | 3769 | ||
3607 | static void dsi_config_vp_num_line_buffers(struct omap_dss_device *dssdev) | 3770 | static void dsi_config_vp_num_line_buffers(struct platform_device *dsidev) |
3608 | { | 3771 | { |
3609 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 3772 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
3610 | int num_line_buffers; | 3773 | int num_line_buffers; |
3611 | 3774 | ||
3612 | if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { | 3775 | if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { |
3613 | int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); | 3776 | int bpp = dsi_get_pixel_size(dsi->pix_fmt); |
3614 | unsigned line_buf_size = dsi_get_line_buf_size(dsidev); | 3777 | unsigned line_buf_size = dsi_get_line_buf_size(dsidev); |
3615 | struct omap_video_timings *timings = &dssdev->panel.timings; | 3778 | struct omap_video_timings *timings = &dsi->timings; |
3616 | /* | 3779 | /* |
3617 | * Don't use line buffers if width is greater than the video | 3780 | * Don't use line buffers if width is greater than the video |
3618 | * port's line buffer size | 3781 | * port's line buffer size |
@@ -3630,11 +3793,11 @@ static void dsi_config_vp_num_line_buffers(struct omap_dss_device *dssdev) | |||
3630 | REG_FLD_MOD(dsidev, DSI_CTRL, num_line_buffers, 13, 12); | 3793 | REG_FLD_MOD(dsidev, DSI_CTRL, num_line_buffers, 13, 12); |
3631 | } | 3794 | } |
3632 | 3795 | ||
3633 | static void dsi_config_vp_sync_events(struct omap_dss_device *dssdev) | 3796 | static void dsi_config_vp_sync_events(struct platform_device *dsidev) |
3634 | { | 3797 | { |
3635 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 3798 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
3636 | bool vsync_end = dssdev->panel.dsi_vm_data.vp_vsync_end; | 3799 | bool vsync_end = dsi->vm_timings.vp_vsync_end; |
3637 | bool hsync_end = dssdev->panel.dsi_vm_data.vp_hsync_end; | 3800 | bool hsync_end = dsi->vm_timings.vp_hsync_end; |
3638 | u32 r; | 3801 | u32 r; |
3639 | 3802 | ||
3640 | r = dsi_read_reg(dsidev, DSI_CTRL); | 3803 | r = dsi_read_reg(dsidev, DSI_CTRL); |
@@ -3648,13 +3811,13 @@ static void dsi_config_vp_sync_events(struct omap_dss_device *dssdev) | |||
3648 | dsi_write_reg(dsidev, DSI_CTRL, r); | 3811 | dsi_write_reg(dsidev, DSI_CTRL, r); |
3649 | } | 3812 | } |
3650 | 3813 | ||
3651 | static void dsi_config_blanking_modes(struct omap_dss_device *dssdev) | 3814 | static void dsi_config_blanking_modes(struct platform_device *dsidev) |
3652 | { | 3815 | { |
3653 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 3816 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
3654 | int blanking_mode = dssdev->panel.dsi_vm_data.blanking_mode; | 3817 | int blanking_mode = dsi->vm_timings.blanking_mode; |
3655 | int hfp_blanking_mode = dssdev->panel.dsi_vm_data.hfp_blanking_mode; | 3818 | int hfp_blanking_mode = dsi->vm_timings.hfp_blanking_mode; |
3656 | int hbp_blanking_mode = dssdev->panel.dsi_vm_data.hbp_blanking_mode; | 3819 | int hbp_blanking_mode = dsi->vm_timings.hbp_blanking_mode; |
3657 | int hsa_blanking_mode = dssdev->panel.dsi_vm_data.hsa_blanking_mode; | 3820 | int hsa_blanking_mode = dsi->vm_timings.hsa_blanking_mode; |
3658 | u32 r; | 3821 | u32 r; |
3659 | 3822 | ||
3660 | /* | 3823 | /* |
@@ -3741,8 +3904,8 @@ static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev) | |||
3741 | int ddr_clk_pre, ddr_clk_post, enter_hs_mode_lat, exit_hs_mode_lat; | 3904 | int ddr_clk_pre, ddr_clk_post, enter_hs_mode_lat, exit_hs_mode_lat; |
3742 | int tclk_trail, ths_exit, exiths_clk; | 3905 | int tclk_trail, ths_exit, exiths_clk; |
3743 | bool ddr_alwon; | 3906 | bool ddr_alwon; |
3744 | struct omap_video_timings *timings = &dssdev->panel.timings; | 3907 | struct omap_video_timings *timings = &dsi->timings; |
3745 | int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); | 3908 | int bpp = dsi_get_pixel_size(dsi->pix_fmt); |
3746 | int ndl = dsi->num_lanes_used - 1; | 3909 | int ndl = dsi->num_lanes_used - 1; |
3747 | int dsi_fclk_hsdiv = dssdev->clocks.dsi.regm_dsi + 1; | 3910 | int dsi_fclk_hsdiv = dssdev->clocks.dsi.regm_dsi + 1; |
3748 | int hsa_interleave_hs = 0, hsa_interleave_lp = 0; | 3911 | int hsa_interleave_hs = 0, hsa_interleave_lp = 0; |
@@ -3852,6 +4015,7 @@ static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev) | |||
3852 | static int dsi_proto_config(struct omap_dss_device *dssdev) | 4015 | static int dsi_proto_config(struct omap_dss_device *dssdev) |
3853 | { | 4016 | { |
3854 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4017 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
4018 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
3855 | u32 r; | 4019 | u32 r; |
3856 | int buswidth = 0; | 4020 | int buswidth = 0; |
3857 | 4021 | ||
@@ -3871,7 +4035,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) | |||
3871 | dsi_set_lp_rx_timeout(dsidev, 0x1fff, true, true); | 4035 | dsi_set_lp_rx_timeout(dsidev, 0x1fff, true, true); |
3872 | dsi_set_hs_tx_timeout(dsidev, 0x1fff, true, true); | 4036 | dsi_set_hs_tx_timeout(dsidev, 0x1fff, true, true); |
3873 | 4037 | ||
3874 | switch (dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt)) { | 4038 | switch (dsi_get_pixel_size(dsi->pix_fmt)) { |
3875 | case 16: | 4039 | case 16: |
3876 | buswidth = 0; | 4040 | buswidth = 0; |
3877 | break; | 4041 | break; |
@@ -3903,11 +4067,11 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) | |||
3903 | 4067 | ||
3904 | dsi_write_reg(dsidev, DSI_CTRL, r); | 4068 | dsi_write_reg(dsidev, DSI_CTRL, r); |
3905 | 4069 | ||
3906 | dsi_config_vp_num_line_buffers(dssdev); | 4070 | dsi_config_vp_num_line_buffers(dsidev); |
3907 | 4071 | ||
3908 | if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { | 4072 | if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { |
3909 | dsi_config_vp_sync_events(dssdev); | 4073 | dsi_config_vp_sync_events(dsidev); |
3910 | dsi_config_blanking_modes(dssdev); | 4074 | dsi_config_blanking_modes(dsidev); |
3911 | dsi_config_cmd_mode_interleaving(dssdev); | 4075 | dsi_config_cmd_mode_interleaving(dssdev); |
3912 | } | 4076 | } |
3913 | 4077 | ||
@@ -3919,9 +4083,8 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) | |||
3919 | return 0; | 4083 | return 0; |
3920 | } | 4084 | } |
3921 | 4085 | ||
3922 | static void dsi_proto_timings(struct omap_dss_device *dssdev) | 4086 | static void dsi_proto_timings(struct platform_device *dsidev) |
3923 | { | 4087 | { |
3924 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
3925 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4088 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
3926 | unsigned tlpx, tclk_zero, tclk_prepare, tclk_trail; | 4089 | unsigned tlpx, tclk_zero, tclk_prepare, tclk_trail; |
3927 | unsigned tclk_pre, tclk_post; | 4090 | unsigned tclk_pre, tclk_post; |
@@ -3941,7 +4104,7 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev) | |||
3941 | ths_exit = FLD_GET(r, 7, 0); | 4104 | ths_exit = FLD_GET(r, 7, 0); |
3942 | 4105 | ||
3943 | r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1); | 4106 | r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1); |
3944 | tlpx = FLD_GET(r, 22, 16) * 2; | 4107 | tlpx = FLD_GET(r, 20, 16) * 2; |
3945 | tclk_trail = FLD_GET(r, 15, 8); | 4108 | tclk_trail = FLD_GET(r, 15, 8); |
3946 | tclk_zero = FLD_GET(r, 7, 0); | 4109 | tclk_zero = FLD_GET(r, 7, 0); |
3947 | 4110 | ||
@@ -3984,18 +4147,18 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev) | |||
3984 | DSSDBG("enter_hs_mode_lat %u, exit_hs_mode_lat %u\n", | 4147 | DSSDBG("enter_hs_mode_lat %u, exit_hs_mode_lat %u\n", |
3985 | enter_hs_mode_lat, exit_hs_mode_lat); | 4148 | enter_hs_mode_lat, exit_hs_mode_lat); |
3986 | 4149 | ||
3987 | if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { | 4150 | if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { |
3988 | /* TODO: Implement a video mode check_timings function */ | 4151 | /* TODO: Implement a video mode check_timings function */ |
3989 | int hsa = dssdev->panel.dsi_vm_data.hsa; | 4152 | int hsa = dsi->vm_timings.hsa; |
3990 | int hfp = dssdev->panel.dsi_vm_data.hfp; | 4153 | int hfp = dsi->vm_timings.hfp; |
3991 | int hbp = dssdev->panel.dsi_vm_data.hbp; | 4154 | int hbp = dsi->vm_timings.hbp; |
3992 | int vsa = dssdev->panel.dsi_vm_data.vsa; | 4155 | int vsa = dsi->vm_timings.vsa; |
3993 | int vfp = dssdev->panel.dsi_vm_data.vfp; | 4156 | int vfp = dsi->vm_timings.vfp; |
3994 | int vbp = dssdev->panel.dsi_vm_data.vbp; | 4157 | int vbp = dsi->vm_timings.vbp; |
3995 | int window_sync = dssdev->panel.dsi_vm_data.window_sync; | 4158 | int window_sync = dsi->vm_timings.window_sync; |
3996 | bool hsync_end = dssdev->panel.dsi_vm_data.vp_hsync_end; | 4159 | bool hsync_end = dsi->vm_timings.vp_hsync_end; |
3997 | struct omap_video_timings *timings = &dssdev->panel.timings; | 4160 | struct omap_video_timings *timings = &dsi->timings; |
3998 | int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); | 4161 | int bpp = dsi_get_pixel_size(dsi->pix_fmt); |
3999 | int tl, t_he, width_bytes; | 4162 | int tl, t_he, width_bytes; |
4000 | 4163 | ||
4001 | t_he = hsync_end ? | 4164 | t_he = hsync_end ? |
@@ -4100,16 +4263,84 @@ int omapdss_dsi_configure_pins(struct omap_dss_device *dssdev, | |||
4100 | } | 4263 | } |
4101 | EXPORT_SYMBOL(omapdss_dsi_configure_pins); | 4264 | EXPORT_SYMBOL(omapdss_dsi_configure_pins); |
4102 | 4265 | ||
4103 | int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) | 4266 | int omapdss_dsi_set_clocks(struct omap_dss_device *dssdev, |
4267 | unsigned long ddr_clk, unsigned long lp_clk) | ||
4104 | { | 4268 | { |
4105 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4269 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
4270 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
4271 | struct dsi_clock_info cinfo; | ||
4272 | struct dispc_clock_info dispc_cinfo; | ||
4273 | unsigned lp_clk_div; | ||
4274 | unsigned long dsi_fclk; | ||
4106 | int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); | 4275 | int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); |
4276 | unsigned long pck; | ||
4277 | int r; | ||
4278 | |||
4279 | DSSDBGF("ddr_clk %lu, lp_clk %lu", ddr_clk, lp_clk); | ||
4280 | |||
4281 | mutex_lock(&dsi->lock); | ||
4282 | |||
4283 | /* Calculate PLL output clock */ | ||
4284 | r = dsi_pll_calc_ddrfreq(dsidev, ddr_clk * 4, &cinfo); | ||
4285 | if (r) | ||
4286 | goto err; | ||
4287 | |||
4288 | /* Calculate PLL's DSI clock */ | ||
4289 | dsi_pll_calc_dsi_fck(dsidev, &cinfo); | ||
4290 | |||
4291 | /* Calculate PLL's DISPC clock and pck & lck divs */ | ||
4292 | pck = cinfo.clkin4ddr / 16 * (dsi->num_lanes_used - 1) * 8 / bpp; | ||
4293 | DSSDBG("finding dispc dividers for pck %lu\n", pck); | ||
4294 | r = dsi_pll_calc_dispc_fck(dsidev, pck, &cinfo, &dispc_cinfo); | ||
4295 | if (r) | ||
4296 | goto err; | ||
4297 | |||
4298 | /* Calculate LP clock */ | ||
4299 | dsi_fclk = cinfo.dsi_pll_hsdiv_dsi_clk; | ||
4300 | lp_clk_div = DIV_ROUND_UP(dsi_fclk, lp_clk * 2); | ||
4301 | |||
4302 | dssdev->clocks.dsi.regn = cinfo.regn; | ||
4303 | dssdev->clocks.dsi.regm = cinfo.regm; | ||
4304 | dssdev->clocks.dsi.regm_dispc = cinfo.regm_dispc; | ||
4305 | dssdev->clocks.dsi.regm_dsi = cinfo.regm_dsi; | ||
4306 | |||
4307 | dssdev->clocks.dsi.lp_clk_div = lp_clk_div; | ||
4308 | |||
4309 | dssdev->clocks.dispc.channel.lck_div = dispc_cinfo.lck_div; | ||
4310 | dssdev->clocks.dispc.channel.pck_div = dispc_cinfo.pck_div; | ||
4311 | |||
4312 | dssdev->clocks.dispc.dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK; | ||
4313 | |||
4314 | dssdev->clocks.dispc.channel.lcd_clk_src = | ||
4315 | dsi->module_id == 0 ? | ||
4316 | OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC : | ||
4317 | OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC; | ||
4318 | |||
4319 | dssdev->clocks.dsi.dsi_fclk_src = | ||
4320 | dsi->module_id == 0 ? | ||
4321 | OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI : | ||
4322 | OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI; | ||
4323 | |||
4324 | mutex_unlock(&dsi->lock); | ||
4325 | return 0; | ||
4326 | err: | ||
4327 | mutex_unlock(&dsi->lock); | ||
4328 | return r; | ||
4329 | } | ||
4330 | EXPORT_SYMBOL(omapdss_dsi_set_clocks); | ||
4331 | |||
4332 | int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) | ||
4333 | { | ||
4334 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
4335 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
4336 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
4337 | int bpp = dsi_get_pixel_size(dsi->pix_fmt); | ||
4107 | u8 data_type; | 4338 | u8 data_type; |
4108 | u16 word_count; | 4339 | u16 word_count; |
4109 | int r; | 4340 | int r; |
4110 | 4341 | ||
4111 | if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { | 4342 | if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { |
4112 | switch (dssdev->panel.dsi_pix_fmt) { | 4343 | switch (dsi->pix_fmt) { |
4113 | case OMAP_DSS_DSI_FMT_RGB888: | 4344 | case OMAP_DSS_DSI_FMT_RGB888: |
4114 | data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24; | 4345 | data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24; |
4115 | break; | 4346 | break; |
@@ -4133,7 +4364,7 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) | |||
4133 | /* MODE, 1 = video mode */ | 4364 | /* MODE, 1 = video mode */ |
4134 | REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 4, 4); | 4365 | REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 4, 4); |
4135 | 4366 | ||
4136 | word_count = DIV_ROUND_UP(dssdev->panel.timings.x_res * bpp, 8); | 4367 | word_count = DIV_ROUND_UP(dsi->timings.x_res * bpp, 8); |
4137 | 4368 | ||
4138 | dsi_vc_write_long_header(dsidev, channel, data_type, | 4369 | dsi_vc_write_long_header(dsidev, channel, data_type, |
4139 | word_count, 0); | 4370 | word_count, 0); |
@@ -4142,9 +4373,9 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) | |||
4142 | dsi_if_enable(dsidev, true); | 4373 | dsi_if_enable(dsidev, true); |
4143 | } | 4374 | } |
4144 | 4375 | ||
4145 | r = dss_mgr_enable(dssdev->manager); | 4376 | r = dss_mgr_enable(mgr); |
4146 | if (r) { | 4377 | if (r) { |
4147 | if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { | 4378 | if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { |
4148 | dsi_if_enable(dsidev, false); | 4379 | dsi_if_enable(dsidev, false); |
4149 | dsi_vc_enable(dsidev, channel, false); | 4380 | dsi_vc_enable(dsidev, channel, false); |
4150 | } | 4381 | } |
@@ -4159,8 +4390,10 @@ EXPORT_SYMBOL(dsi_enable_video_output); | |||
4159 | void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel) | 4390 | void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel) |
4160 | { | 4391 | { |
4161 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4392 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
4393 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
4394 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
4162 | 4395 | ||
4163 | if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { | 4396 | if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { |
4164 | dsi_if_enable(dsidev, false); | 4397 | dsi_if_enable(dsidev, false); |
4165 | dsi_vc_enable(dsidev, channel, false); | 4398 | dsi_vc_enable(dsidev, channel, false); |
4166 | 4399 | ||
@@ -4171,15 +4404,15 @@ void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel) | |||
4171 | dsi_if_enable(dsidev, true); | 4404 | dsi_if_enable(dsidev, true); |
4172 | } | 4405 | } |
4173 | 4406 | ||
4174 | dss_mgr_disable(dssdev->manager); | 4407 | dss_mgr_disable(mgr); |
4175 | } | 4408 | } |
4176 | EXPORT_SYMBOL(dsi_disable_video_output); | 4409 | EXPORT_SYMBOL(dsi_disable_video_output); |
4177 | 4410 | ||
4178 | static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, | 4411 | static void dsi_update_screen_dispc(struct omap_dss_device *dssdev) |
4179 | u16 w, u16 h) | ||
4180 | { | 4412 | { |
4181 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4413 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
4182 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4414 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
4415 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
4183 | unsigned bytespp; | 4416 | unsigned bytespp; |
4184 | unsigned bytespl; | 4417 | unsigned bytespl; |
4185 | unsigned bytespf; | 4418 | unsigned bytespf; |
@@ -4190,12 +4423,14 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, | |||
4190 | int r; | 4423 | int r; |
4191 | const unsigned channel = dsi->update_channel; | 4424 | const unsigned channel = dsi->update_channel; |
4192 | const unsigned line_buf_size = dsi_get_line_buf_size(dsidev); | 4425 | const unsigned line_buf_size = dsi_get_line_buf_size(dsidev); |
4426 | u16 w = dsi->timings.x_res; | ||
4427 | u16 h = dsi->timings.y_res; | ||
4193 | 4428 | ||
4194 | DSSDBG("dsi_update_screen_dispc(%dx%d)\n", w, h); | 4429 | DSSDBG("dsi_update_screen_dispc(%dx%d)\n", w, h); |
4195 | 4430 | ||
4196 | dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_VP); | 4431 | dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_VP); |
4197 | 4432 | ||
4198 | bytespp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) / 8; | 4433 | bytespp = dsi_get_pixel_size(dsi->pix_fmt) / 8; |
4199 | bytespl = w * bytespp; | 4434 | bytespl = w * bytespp; |
4200 | bytespf = bytespl * h; | 4435 | bytespf = bytespl * h; |
4201 | 4436 | ||
@@ -4239,7 +4474,9 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, | |||
4239 | msecs_to_jiffies(250)); | 4474 | msecs_to_jiffies(250)); |
4240 | BUG_ON(r == 0); | 4475 | BUG_ON(r == 0); |
4241 | 4476 | ||
4242 | dss_mgr_start_update(dssdev->manager); | 4477 | dss_mgr_set_timings(mgr, &dsi->timings); |
4478 | |||
4479 | dss_mgr_start_update(mgr); | ||
4243 | 4480 | ||
4244 | if (dsi->te_enabled) { | 4481 | if (dsi->te_enabled) { |
4245 | /* disable LP_RX_TO, so that we can receive TE. Time to wait | 4482 | /* disable LP_RX_TO, so that we can receive TE. Time to wait |
@@ -4297,8 +4534,7 @@ static void dsi_framedone_timeout_work_callback(struct work_struct *work) | |||
4297 | 4534 | ||
4298 | static void dsi_framedone_irq_callback(void *data, u32 mask) | 4535 | static void dsi_framedone_irq_callback(void *data, u32 mask) |
4299 | { | 4536 | { |
4300 | struct omap_dss_device *dssdev = (struct omap_dss_device *) data; | 4537 | struct platform_device *dsidev = (struct platform_device *) data; |
4301 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
4302 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4538 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
4303 | 4539 | ||
4304 | /* Note: We get FRAMEDONE when DISPC has finished sending pixels and | 4540 | /* Note: We get FRAMEDONE when DISPC has finished sending pixels and |
@@ -4325,13 +4561,14 @@ int omap_dsi_update(struct omap_dss_device *dssdev, int channel, | |||
4325 | dsi->framedone_callback = callback; | 4561 | dsi->framedone_callback = callback; |
4326 | dsi->framedone_data = data; | 4562 | dsi->framedone_data = data; |
4327 | 4563 | ||
4328 | dssdev->driver->get_resolution(dssdev, &dw, &dh); | 4564 | dw = dsi->timings.x_res; |
4565 | dh = dsi->timings.y_res; | ||
4329 | 4566 | ||
4330 | #ifdef DEBUG | 4567 | #ifdef DEBUG |
4331 | dsi->update_bytes = dw * dh * | 4568 | dsi->update_bytes = dw * dh * |
4332 | dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) / 8; | 4569 | dsi_get_pixel_size(dsi->pix_fmt) / 8; |
4333 | #endif | 4570 | #endif |
4334 | dsi_update_screen_dispc(dssdev, dw, dh); | 4571 | dsi_update_screen_dispc(dssdev); |
4335 | 4572 | ||
4336 | return 0; | 4573 | return 0; |
4337 | } | 4574 | } |
@@ -4367,28 +4604,22 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) | |||
4367 | { | 4604 | { |
4368 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4605 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
4369 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4606 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
4370 | struct omap_video_timings timings; | 4607 | struct omap_overlay_manager *mgr = dssdev->output->manager; |
4371 | int r; | 4608 | int r; |
4372 | u32 irq = 0; | 4609 | u32 irq = 0; |
4373 | 4610 | ||
4374 | if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) { | 4611 | if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) { |
4375 | u16 dw, dh; | 4612 | dsi->timings.hsw = 1; |
4376 | 4613 | dsi->timings.hfp = 1; | |
4377 | dssdev->driver->get_resolution(dssdev, &dw, &dh); | 4614 | dsi->timings.hbp = 1; |
4378 | 4615 | dsi->timings.vsw = 1; | |
4379 | timings.x_res = dw; | 4616 | dsi->timings.vfp = 0; |
4380 | timings.y_res = dh; | 4617 | dsi->timings.vbp = 0; |
4381 | timings.hsw = 1; | ||
4382 | timings.hfp = 1; | ||
4383 | timings.hbp = 1; | ||
4384 | timings.vsw = 1; | ||
4385 | timings.vfp = 0; | ||
4386 | timings.vbp = 0; | ||
4387 | 4618 | ||
4388 | irq = dispc_mgr_get_framedone_irq(dssdev->manager->id); | 4619 | irq = dispc_mgr_get_framedone_irq(mgr->id); |
4389 | 4620 | ||
4390 | r = omap_dispc_register_isr(dsi_framedone_irq_callback, | 4621 | r = omap_dispc_register_isr(dsi_framedone_irq_callback, |
4391 | (void *) dssdev, irq); | 4622 | (void *) dsidev, irq); |
4392 | if (r) { | 4623 | if (r) { |
4393 | DSSERR("can't get FRAMEDONE irq\n"); | 4624 | DSSERR("can't get FRAMEDONE irq\n"); |
4394 | goto err; | 4625 | goto err; |
@@ -4397,8 +4628,6 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) | |||
4397 | dsi->mgr_config.stallmode = true; | 4628 | dsi->mgr_config.stallmode = true; |
4398 | dsi->mgr_config.fifohandcheck = true; | 4629 | dsi->mgr_config.fifohandcheck = true; |
4399 | } else { | 4630 | } else { |
4400 | timings = dssdev->panel.timings; | ||
4401 | |||
4402 | dsi->mgr_config.stallmode = false; | 4631 | dsi->mgr_config.stallmode = false; |
4403 | dsi->mgr_config.fifohandcheck = false; | 4632 | dsi->mgr_config.fifohandcheck = false; |
4404 | } | 4633 | } |
@@ -4407,14 +4636,14 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) | |||
4407 | * override interlace, logic level and edge related parameters in | 4636 | * override interlace, logic level and edge related parameters in |
4408 | * omap_video_timings with default values | 4637 | * omap_video_timings with default values |
4409 | */ | 4638 | */ |
4410 | timings.interlace = false; | 4639 | dsi->timings.interlace = false; |
4411 | timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH; | 4640 | dsi->timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH; |
4412 | timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH; | 4641 | dsi->timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH; |
4413 | timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; | 4642 | dsi->timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; |
4414 | timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH; | 4643 | dsi->timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH; |
4415 | timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; | 4644 | dsi->timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; |
4416 | 4645 | ||
4417 | dss_mgr_set_timings(dssdev->manager, &timings); | 4646 | dss_mgr_set_timings(mgr, &dsi->timings); |
4418 | 4647 | ||
4419 | r = dsi_configure_dispc_clocks(dssdev); | 4648 | r = dsi_configure_dispc_clocks(dssdev); |
4420 | if (r) | 4649 | if (r) |
@@ -4422,29 +4651,33 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) | |||
4422 | 4651 | ||
4423 | dsi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; | 4652 | dsi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; |
4424 | dsi->mgr_config.video_port_width = | 4653 | dsi->mgr_config.video_port_width = |
4425 | dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); | 4654 | dsi_get_pixel_size(dsi->pix_fmt); |
4426 | dsi->mgr_config.lcden_sig_polarity = 0; | 4655 | dsi->mgr_config.lcden_sig_polarity = 0; |
4427 | 4656 | ||
4428 | dss_mgr_set_lcd_config(dssdev->manager, &dsi->mgr_config); | 4657 | dss_mgr_set_lcd_config(mgr, &dsi->mgr_config); |
4429 | 4658 | ||
4430 | return 0; | 4659 | return 0; |
4431 | err1: | 4660 | err1: |
4432 | if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) | 4661 | if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) |
4433 | omap_dispc_unregister_isr(dsi_framedone_irq_callback, | 4662 | omap_dispc_unregister_isr(dsi_framedone_irq_callback, |
4434 | (void *) dssdev, irq); | 4663 | (void *) dsidev, irq); |
4435 | err: | 4664 | err: |
4436 | return r; | 4665 | return r; |
4437 | } | 4666 | } |
4438 | 4667 | ||
4439 | static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev) | 4668 | static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev) |
4440 | { | 4669 | { |
4441 | if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) { | 4670 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
4671 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
4672 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
4673 | |||
4674 | if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) { | ||
4442 | u32 irq; | 4675 | u32 irq; |
4443 | 4676 | ||
4444 | irq = dispc_mgr_get_framedone_irq(dssdev->manager->id); | 4677 | irq = dispc_mgr_get_framedone_irq(mgr->id); |
4445 | 4678 | ||
4446 | omap_dispc_unregister_isr(dsi_framedone_irq_callback, | 4679 | omap_dispc_unregister_isr(dsi_framedone_irq_callback, |
4447 | (void *) dssdev, irq); | 4680 | (void *) dsidev, irq); |
4448 | } | 4681 | } |
4449 | } | 4682 | } |
4450 | 4683 | ||
@@ -4477,6 +4710,7 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) | |||
4477 | { | 4710 | { |
4478 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4711 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
4479 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4712 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
4713 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
4480 | int r; | 4714 | int r; |
4481 | 4715 | ||
4482 | r = dsi_pll_init(dsidev, true, true); | 4716 | r = dsi_pll_init(dsidev, true, true); |
@@ -4489,18 +4723,18 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) | |||
4489 | 4723 | ||
4490 | dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src); | 4724 | dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src); |
4491 | dss_select_dsi_clk_source(dsi->module_id, dssdev->clocks.dsi.dsi_fclk_src); | 4725 | dss_select_dsi_clk_source(dsi->module_id, dssdev->clocks.dsi.dsi_fclk_src); |
4492 | dss_select_lcd_clk_source(dssdev->manager->id, | 4726 | dss_select_lcd_clk_source(mgr->id, |
4493 | dssdev->clocks.dispc.channel.lcd_clk_src); | 4727 | dssdev->clocks.dispc.channel.lcd_clk_src); |
4494 | 4728 | ||
4495 | DSSDBG("PLL OK\n"); | 4729 | DSSDBG("PLL OK\n"); |
4496 | 4730 | ||
4497 | r = dsi_cio_init(dssdev); | 4731 | r = dsi_cio_init(dsidev); |
4498 | if (r) | 4732 | if (r) |
4499 | goto err2; | 4733 | goto err2; |
4500 | 4734 | ||
4501 | _dsi_print_reset_status(dsidev); | 4735 | _dsi_print_reset_status(dsidev); |
4502 | 4736 | ||
4503 | dsi_proto_timings(dssdev); | 4737 | dsi_proto_timings(dsidev); |
4504 | dsi_set_lp_clk_divisor(dssdev); | 4738 | dsi_set_lp_clk_divisor(dssdev); |
4505 | 4739 | ||
4506 | if (1) | 4740 | if (1) |
@@ -4520,11 +4754,11 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) | |||
4520 | 4754 | ||
4521 | return 0; | 4755 | return 0; |
4522 | err3: | 4756 | err3: |
4523 | dsi_cio_uninit(dssdev); | 4757 | dsi_cio_uninit(dsidev); |
4524 | err2: | 4758 | err2: |
4525 | dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); | 4759 | dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); |
4526 | dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK); | 4760 | dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK); |
4527 | dss_select_lcd_clk_source(dssdev->manager->id, OMAP_DSS_CLK_SRC_FCK); | 4761 | dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); |
4528 | 4762 | ||
4529 | err1: | 4763 | err1: |
4530 | dsi_pll_uninit(dsidev, true); | 4764 | dsi_pll_uninit(dsidev, true); |
@@ -4537,6 +4771,7 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev, | |||
4537 | { | 4771 | { |
4538 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4772 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
4539 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4773 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
4774 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
4540 | 4775 | ||
4541 | if (enter_ulps && !dsi->ulps_enabled) | 4776 | if (enter_ulps && !dsi->ulps_enabled) |
4542 | dsi_enter_ulps(dsidev); | 4777 | dsi_enter_ulps(dsidev); |
@@ -4550,8 +4785,8 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev, | |||
4550 | 4785 | ||
4551 | dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); | 4786 | dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); |
4552 | dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK); | 4787 | dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK); |
4553 | dss_select_lcd_clk_source(dssdev->manager->id, OMAP_DSS_CLK_SRC_FCK); | 4788 | dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); |
4554 | dsi_cio_uninit(dssdev); | 4789 | dsi_cio_uninit(dsidev); |
4555 | dsi_pll_uninit(dsidev, disconnect_lanes); | 4790 | dsi_pll_uninit(dsidev, disconnect_lanes); |
4556 | } | 4791 | } |
4557 | 4792 | ||
@@ -4559,6 +4794,7 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev) | |||
4559 | { | 4794 | { |
4560 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4795 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
4561 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4796 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
4797 | struct omap_dss_output *out = dssdev->output; | ||
4562 | int r = 0; | 4798 | int r = 0; |
4563 | 4799 | ||
4564 | DSSDBG("dsi_display_enable\n"); | 4800 | DSSDBG("dsi_display_enable\n"); |
@@ -4567,8 +4803,8 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev) | |||
4567 | 4803 | ||
4568 | mutex_lock(&dsi->lock); | 4804 | mutex_lock(&dsi->lock); |
4569 | 4805 | ||
4570 | if (dssdev->manager == NULL) { | 4806 | if (out == NULL || out->manager == NULL) { |
4571 | DSSERR("failed to enable display: no manager\n"); | 4807 | DSSERR("failed to enable display: no output/manager\n"); |
4572 | r = -ENODEV; | 4808 | r = -ENODEV; |
4573 | goto err_start_dev; | 4809 | goto err_start_dev; |
4574 | } | 4810 | } |
@@ -4653,17 +4889,83 @@ int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable) | |||
4653 | } | 4889 | } |
4654 | EXPORT_SYMBOL(omapdss_dsi_enable_te); | 4890 | EXPORT_SYMBOL(omapdss_dsi_enable_te); |
4655 | 4891 | ||
4656 | static int __init dsi_init_display(struct omap_dss_device *dssdev) | 4892 | void omapdss_dsi_set_timings(struct omap_dss_device *dssdev, |
4893 | struct omap_video_timings *timings) | ||
4657 | { | 4894 | { |
4658 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4895 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
4659 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4896 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
4660 | 4897 | ||
4661 | DSSDBG("DSI init\n"); | 4898 | mutex_lock(&dsi->lock); |
4662 | 4899 | ||
4663 | if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) { | 4900 | dsi->timings = *timings; |
4664 | dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE | | 4901 | |
4665 | OMAP_DSS_DISPLAY_CAP_TEAR_ELIM; | 4902 | mutex_unlock(&dsi->lock); |
4666 | } | 4903 | } |
4904 | EXPORT_SYMBOL(omapdss_dsi_set_timings); | ||
4905 | |||
4906 | void omapdss_dsi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h) | ||
4907 | { | ||
4908 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
4909 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
4910 | |||
4911 | mutex_lock(&dsi->lock); | ||
4912 | |||
4913 | dsi->timings.x_res = w; | ||
4914 | dsi->timings.y_res = h; | ||
4915 | |||
4916 | mutex_unlock(&dsi->lock); | ||
4917 | } | ||
4918 | EXPORT_SYMBOL(omapdss_dsi_set_size); | ||
4919 | |||
4920 | void omapdss_dsi_set_pixel_format(struct omap_dss_device *dssdev, | ||
4921 | enum omap_dss_dsi_pixel_format fmt) | ||
4922 | { | ||
4923 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
4924 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
4925 | |||
4926 | mutex_lock(&dsi->lock); | ||
4927 | |||
4928 | dsi->pix_fmt = fmt; | ||
4929 | |||
4930 | mutex_unlock(&dsi->lock); | ||
4931 | } | ||
4932 | EXPORT_SYMBOL(omapdss_dsi_set_pixel_format); | ||
4933 | |||
4934 | void omapdss_dsi_set_operation_mode(struct omap_dss_device *dssdev, | ||
4935 | enum omap_dss_dsi_mode mode) | ||
4936 | { | ||
4937 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
4938 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
4939 | |||
4940 | mutex_lock(&dsi->lock); | ||
4941 | |||
4942 | dsi->mode = mode; | ||
4943 | |||
4944 | mutex_unlock(&dsi->lock); | ||
4945 | } | ||
4946 | EXPORT_SYMBOL(omapdss_dsi_set_operation_mode); | ||
4947 | |||
4948 | void omapdss_dsi_set_videomode_timings(struct omap_dss_device *dssdev, | ||
4949 | struct omap_dss_dsi_videomode_timings *timings) | ||
4950 | { | ||
4951 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
4952 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
4953 | |||
4954 | mutex_lock(&dsi->lock); | ||
4955 | |||
4956 | dsi->vm_timings = *timings; | ||
4957 | |||
4958 | mutex_unlock(&dsi->lock); | ||
4959 | } | ||
4960 | EXPORT_SYMBOL(omapdss_dsi_set_videomode_timings); | ||
4961 | |||
4962 | static int __init dsi_init_display(struct omap_dss_device *dssdev) | ||
4963 | { | ||
4964 | struct platform_device *dsidev = | ||
4965 | dsi_get_dsidev_from_id(dssdev->phy.dsi.module); | ||
4966 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
4967 | |||
4968 | DSSDBG("DSI init\n"); | ||
4667 | 4969 | ||
4668 | if (dsi->vdds_dsi_reg == NULL) { | 4970 | if (dsi->vdds_dsi_reg == NULL) { |
4669 | struct regulator *vdds_dsi; | 4971 | struct regulator *vdds_dsi; |
@@ -4806,11 +5108,15 @@ static void dsi_put_clocks(struct platform_device *dsidev) | |||
4806 | clk_put(dsi->sys_clk); | 5108 | clk_put(dsi->sys_clk); |
4807 | } | 5109 | } |
4808 | 5110 | ||
4809 | static void __init dsi_probe_pdata(struct platform_device *dsidev) | 5111 | static struct omap_dss_device * __init dsi_find_dssdev(struct platform_device *pdev) |
4810 | { | 5112 | { |
4811 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 5113 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; |
4812 | struct omap_dss_board_info *pdata = dsidev->dev.platform_data; | 5114 | struct dsi_data *dsi = dsi_get_dsidrv_data(pdev); |
4813 | int i, r; | 5115 | const char *def_disp_name = dss_get_default_display_name(); |
5116 | struct omap_dss_device *def_dssdev; | ||
5117 | int i; | ||
5118 | |||
5119 | def_dssdev = NULL; | ||
4814 | 5120 | ||
4815 | for (i = 0; i < pdata->num_devices; ++i) { | 5121 | for (i = 0; i < pdata->num_devices; ++i) { |
4816 | struct omap_dss_device *dssdev = pdata->devices[i]; | 5122 | struct omap_dss_device *dssdev = pdata->devices[i]; |
@@ -4821,19 +5127,73 @@ static void __init dsi_probe_pdata(struct platform_device *dsidev) | |||
4821 | if (dssdev->phy.dsi.module != dsi->module_id) | 5127 | if (dssdev->phy.dsi.module != dsi->module_id) |
4822 | continue; | 5128 | continue; |
4823 | 5129 | ||
4824 | r = dsi_init_display(dssdev); | 5130 | if (def_dssdev == NULL) |
4825 | if (r) { | 5131 | def_dssdev = dssdev; |
4826 | DSSERR("device %s init failed: %d\n", dssdev->name, r); | 5132 | |
4827 | continue; | 5133 | if (def_disp_name != NULL && |
5134 | strcmp(dssdev->name, def_disp_name) == 0) { | ||
5135 | def_dssdev = dssdev; | ||
5136 | break; | ||
4828 | } | 5137 | } |
5138 | } | ||
4829 | 5139 | ||
4830 | r = omap_dss_register_device(dssdev, &dsidev->dev, i); | 5140 | return def_dssdev; |
4831 | if (r) | 5141 | } |
4832 | DSSERR("device %s register failed: %d\n", | 5142 | |
4833 | dssdev->name, r); | 5143 | static void __init dsi_probe_pdata(struct platform_device *dsidev) |
5144 | { | ||
5145 | struct omap_dss_device *plat_dssdev; | ||
5146 | struct omap_dss_device *dssdev; | ||
5147 | int r; | ||
5148 | |||
5149 | plat_dssdev = dsi_find_dssdev(dsidev); | ||
5150 | |||
5151 | if (!plat_dssdev) | ||
5152 | return; | ||
5153 | |||
5154 | dssdev = dss_alloc_and_init_device(&dsidev->dev); | ||
5155 | if (!dssdev) | ||
5156 | return; | ||
5157 | |||
5158 | dss_copy_device_pdata(dssdev, plat_dssdev); | ||
5159 | |||
5160 | r = dsi_init_display(dssdev); | ||
5161 | if (r) { | ||
5162 | DSSERR("device %s init failed: %d\n", dssdev->name, r); | ||
5163 | dss_put_device(dssdev); | ||
5164 | return; | ||
5165 | } | ||
5166 | |||
5167 | r = dss_add_device(dssdev); | ||
5168 | if (r) { | ||
5169 | DSSERR("device %s register failed: %d\n", dssdev->name, r); | ||
5170 | dss_put_device(dssdev); | ||
5171 | return; | ||
4834 | } | 5172 | } |
4835 | } | 5173 | } |
4836 | 5174 | ||
5175 | static void __init dsi_init_output(struct platform_device *dsidev) | ||
5176 | { | ||
5177 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
5178 | struct omap_dss_output *out = &dsi->output; | ||
5179 | |||
5180 | out->pdev = dsidev; | ||
5181 | out->id = dsi->module_id == 0 ? | ||
5182 | OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2; | ||
5183 | |||
5184 | out->type = OMAP_DISPLAY_TYPE_DSI; | ||
5185 | |||
5186 | dss_register_output(out); | ||
5187 | } | ||
5188 | |||
5189 | static void __exit dsi_uninit_output(struct platform_device *dsidev) | ||
5190 | { | ||
5191 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
5192 | struct omap_dss_output *out = &dsi->output; | ||
5193 | |||
5194 | dss_unregister_output(out); | ||
5195 | } | ||
5196 | |||
4837 | /* DSI1 HW IP initialisation */ | 5197 | /* DSI1 HW IP initialisation */ |
4838 | static int __init omap_dsihw_probe(struct platform_device *dsidev) | 5198 | static int __init omap_dsihw_probe(struct platform_device *dsidev) |
4839 | { | 5199 | { |
@@ -4848,7 +5208,6 @@ static int __init omap_dsihw_probe(struct platform_device *dsidev) | |||
4848 | 5208 | ||
4849 | dsi->module_id = dsidev->id; | 5209 | dsi->module_id = dsidev->id; |
4850 | dsi->pdev = dsidev; | 5210 | dsi->pdev = dsidev; |
4851 | dsi_pdev_map[dsi->module_id] = dsidev; | ||
4852 | dev_set_drvdata(&dsidev->dev, dsi); | 5211 | dev_set_drvdata(&dsidev->dev, dsi); |
4853 | 5212 | ||
4854 | spin_lock_init(&dsi->irq_lock); | 5213 | spin_lock_init(&dsi->irq_lock); |
@@ -4928,6 +5287,8 @@ static int __init omap_dsihw_probe(struct platform_device *dsidev) | |||
4928 | else | 5287 | else |
4929 | dsi->num_lanes_supported = 3; | 5288 | dsi->num_lanes_supported = 3; |
4930 | 5289 | ||
5290 | dsi_init_output(dsidev); | ||
5291 | |||
4931 | dsi_probe_pdata(dsidev); | 5292 | dsi_probe_pdata(dsidev); |
4932 | 5293 | ||
4933 | dsi_runtime_put(dsidev); | 5294 | dsi_runtime_put(dsidev); |
@@ -4957,7 +5318,9 @@ static int __exit omap_dsihw_remove(struct platform_device *dsidev) | |||
4957 | 5318 | ||
4958 | WARN_ON(dsi->scp_clk_refcount > 0); | 5319 | WARN_ON(dsi->scp_clk_refcount > 0); |
4959 | 5320 | ||
4960 | omap_dss_unregister_child_devices(&dsidev->dev); | 5321 | dss_unregister_child_devices(&dsidev->dev); |
5322 | |||
5323 | dsi_uninit_output(dsidev); | ||
4961 | 5324 | ||
4962 | pm_runtime_disable(&dsidev->dev); | 5325 | pm_runtime_disable(&dsidev->dev); |
4963 | 5326 | ||
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 04b4586113e3..2ab1c3e96553 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c | |||
@@ -31,11 +31,11 @@ | |||
31 | #include <linux/clk.h> | 31 | #include <linux/clk.h> |
32 | #include <linux/platform_device.h> | 32 | #include <linux/platform_device.h> |
33 | #include <linux/pm_runtime.h> | 33 | #include <linux/pm_runtime.h> |
34 | #include <linux/gfp.h> | ||
34 | 35 | ||
35 | #include <video/omapdss.h> | 36 | #include <video/omapdss.h> |
36 | 37 | ||
37 | #include <plat/cpu.h> | 38 | #include <plat/cpu.h> |
38 | #include <plat/clock.h> | ||
39 | 39 | ||
40 | #include "dss.h" | 40 | #include "dss.h" |
41 | #include "dss_features.h" | 41 | #include "dss_features.h" |
@@ -65,6 +65,13 @@ struct dss_reg { | |||
65 | static int dss_runtime_get(void); | 65 | static int dss_runtime_get(void); |
66 | static void dss_runtime_put(void); | 66 | static void dss_runtime_put(void); |
67 | 67 | ||
68 | struct dss_features { | ||
69 | u8 fck_div_max; | ||
70 | u8 dss_fck_multiplier; | ||
71 | const char *clk_name; | ||
72 | int (*dpi_select_source)(enum omap_channel channel); | ||
73 | }; | ||
74 | |||
68 | static struct { | 75 | static struct { |
69 | struct platform_device *pdev; | 76 | struct platform_device *pdev; |
70 | void __iomem *base; | 77 | void __iomem *base; |
@@ -83,6 +90,8 @@ static struct { | |||
83 | 90 | ||
84 | bool ctx_valid; | 91 | bool ctx_valid; |
85 | u32 ctx[DSS_SZ_REGS / sizeof(u32)]; | 92 | u32 ctx[DSS_SZ_REGS / sizeof(u32)]; |
93 | |||
94 | const struct dss_features *feat; | ||
86 | } dss; | 95 | } dss; |
87 | 96 | ||
88 | static const char * const dss_generic_clk_source_names[] = { | 97 | static const char * const dss_generic_clk_source_names[] = { |
@@ -144,7 +153,7 @@ static void dss_restore_context(void) | |||
144 | #undef SR | 153 | #undef SR |
145 | #undef RR | 154 | #undef RR |
146 | 155 | ||
147 | void dss_sdi_init(u8 datapairs) | 156 | void dss_sdi_init(int datapairs) |
148 | { | 157 | { |
149 | u32 l; | 158 | u32 l; |
150 | 159 | ||
@@ -236,7 +245,6 @@ const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src) | |||
236 | return dss_generic_clk_source_names[clk_src]; | 245 | return dss_generic_clk_source_names[clk_src]; |
237 | } | 246 | } |
238 | 247 | ||
239 | |||
240 | void dss_dump_clocks(struct seq_file *s) | 248 | void dss_dump_clocks(struct seq_file *s) |
241 | { | 249 | { |
242 | unsigned long dpll4_ck_rate; | 250 | unsigned long dpll4_ck_rate; |
@@ -259,18 +267,10 @@ void dss_dump_clocks(struct seq_file *s) | |||
259 | 267 | ||
260 | seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate); | 268 | seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate); |
261 | 269 | ||
262 | if (cpu_is_omap3630() || cpu_is_omap44xx()) | 270 | seq_printf(s, "%s (%s) = %lu / %lu * %d = %lu\n", |
263 | seq_printf(s, "%s (%s) = %lu / %lu = %lu\n", | 271 | fclk_name, fclk_real_name, dpll4_ck_rate, |
264 | fclk_name, fclk_real_name, | 272 | dpll4_ck_rate / dpll4_m4_ck_rate, |
265 | dpll4_ck_rate, | 273 | dss.feat->dss_fck_multiplier, fclk_rate); |
266 | dpll4_ck_rate / dpll4_m4_ck_rate, | ||
267 | fclk_rate); | ||
268 | else | ||
269 | seq_printf(s, "%s (%s) = %lu / %lu * 2 = %lu\n", | ||
270 | fclk_name, fclk_real_name, | ||
271 | dpll4_ck_rate, | ||
272 | dpll4_ck_rate / dpll4_m4_ck_rate, | ||
273 | fclk_rate); | ||
274 | } else { | 274 | } else { |
275 | seq_printf(s, "%s (%s) = %lu\n", | 275 | seq_printf(s, "%s (%s) = %lu\n", |
276 | fclk_name, fclk_real_name, | 276 | fclk_name, fclk_real_name, |
@@ -431,31 +431,6 @@ enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel) | |||
431 | } | 431 | } |
432 | } | 432 | } |
433 | 433 | ||
434 | /* calculate clock rates using dividers in cinfo */ | ||
435 | int dss_calc_clock_rates(struct dss_clock_info *cinfo) | ||
436 | { | ||
437 | if (dss.dpll4_m4_ck) { | ||
438 | unsigned long prate; | ||
439 | u16 fck_div_max = 16; | ||
440 | |||
441 | if (cpu_is_omap3630() || cpu_is_omap44xx()) | ||
442 | fck_div_max = 32; | ||
443 | |||
444 | if (cinfo->fck_div > fck_div_max || cinfo->fck_div == 0) | ||
445 | return -EINVAL; | ||
446 | |||
447 | prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); | ||
448 | |||
449 | cinfo->fck = prate / cinfo->fck_div; | ||
450 | } else { | ||
451 | if (cinfo->fck_div != 0) | ||
452 | return -EINVAL; | ||
453 | cinfo->fck = clk_get_rate(dss.dss_clk); | ||
454 | } | ||
455 | |||
456 | return 0; | ||
457 | } | ||
458 | |||
459 | int dss_set_clock_div(struct dss_clock_info *cinfo) | 434 | int dss_set_clock_div(struct dss_clock_info *cinfo) |
460 | { | 435 | { |
461 | if (dss.dpll4_m4_ck) { | 436 | if (dss.dpll4_m4_ck) { |
@@ -478,26 +453,6 @@ int dss_set_clock_div(struct dss_clock_info *cinfo) | |||
478 | return 0; | 453 | return 0; |
479 | } | 454 | } |
480 | 455 | ||
481 | int dss_get_clock_div(struct dss_clock_info *cinfo) | ||
482 | { | ||
483 | cinfo->fck = clk_get_rate(dss.dss_clk); | ||
484 | |||
485 | if (dss.dpll4_m4_ck) { | ||
486 | unsigned long prate; | ||
487 | |||
488 | prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); | ||
489 | |||
490 | if (cpu_is_omap3630() || cpu_is_omap44xx()) | ||
491 | cinfo->fck_div = prate / (cinfo->fck); | ||
492 | else | ||
493 | cinfo->fck_div = prate / (cinfo->fck / 2); | ||
494 | } else { | ||
495 | cinfo->fck_div = 0; | ||
496 | } | ||
497 | |||
498 | return 0; | ||
499 | } | ||
500 | |||
501 | unsigned long dss_get_dpll4_rate(void) | 456 | unsigned long dss_get_dpll4_rate(void) |
502 | { | 457 | { |
503 | if (dss.dpll4_m4_ck) | 458 | if (dss.dpll4_m4_ck) |
@@ -515,7 +470,7 @@ int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo, | |||
515 | 470 | ||
516 | unsigned long fck, max_dss_fck; | 471 | unsigned long fck, max_dss_fck; |
517 | 472 | ||
518 | u16 fck_div, fck_div_max = 16; | 473 | u16 fck_div; |
519 | 474 | ||
520 | int match = 0; | 475 | int match = 0; |
521 | int min_fck_per_pck; | 476 | int min_fck_per_pck; |
@@ -525,9 +480,8 @@ int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo, | |||
525 | max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); | 480 | max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); |
526 | 481 | ||
527 | fck = clk_get_rate(dss.dss_clk); | 482 | fck = clk_get_rate(dss.dss_clk); |
528 | if (req_pck == dss.cache_req_pck && | 483 | if (req_pck == dss.cache_req_pck && prate == dss.cache_prate && |
529 | ((cpu_is_omap34xx() && prate == dss.cache_prate) || | 484 | dss.cache_dss_cinfo.fck == fck) { |
530 | dss.cache_dss_cinfo.fck == fck)) { | ||
531 | DSSDBG("dispc clock info found from cache.\n"); | 485 | DSSDBG("dispc clock info found from cache.\n"); |
532 | *dss_cinfo = dss.cache_dss_cinfo; | 486 | *dss_cinfo = dss.cache_dss_cinfo; |
533 | *dispc_cinfo = dss.cache_dispc_cinfo; | 487 | *dispc_cinfo = dss.cache_dispc_cinfo; |
@@ -564,16 +518,10 @@ retry: | |||
564 | 518 | ||
565 | goto found; | 519 | goto found; |
566 | } else { | 520 | } else { |
567 | if (cpu_is_omap3630() || cpu_is_omap44xx()) | 521 | for (fck_div = dss.feat->fck_div_max; fck_div > 0; --fck_div) { |
568 | fck_div_max = 32; | ||
569 | |||
570 | for (fck_div = fck_div_max; fck_div > 0; --fck_div) { | ||
571 | struct dispc_clock_info cur_dispc; | 522 | struct dispc_clock_info cur_dispc; |
572 | 523 | ||
573 | if (fck_div_max == 32) | 524 | fck = prate / fck_div * dss.feat->dss_fck_multiplier; |
574 | fck = prate / fck_div; | ||
575 | else | ||
576 | fck = prate / fck_div * 2; | ||
577 | 525 | ||
578 | if (fck > max_dss_fck) | 526 | if (fck > max_dss_fck) |
579 | continue; | 527 | continue; |
@@ -648,9 +596,18 @@ void dss_set_dac_pwrdn_bgz(bool enable) | |||
648 | REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */ | 596 | REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */ |
649 | } | 597 | } |
650 | 598 | ||
651 | void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select hdmi) | 599 | void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select src) |
652 | { | 600 | { |
653 | REG_FLD_MOD(DSS_CONTROL, hdmi, 15, 15); /* VENC_HDMI_SWITCH */ | 601 | enum omap_display_type dp; |
602 | dp = dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_DIGIT); | ||
603 | |||
604 | /* Complain about invalid selections */ | ||
605 | WARN_ON((src == DSS_VENC_TV_CLK) && !(dp & OMAP_DISPLAY_TYPE_VENC)); | ||
606 | WARN_ON((src == DSS_HDMI_M_PCLK) && !(dp & OMAP_DISPLAY_TYPE_HDMI)); | ||
607 | |||
608 | /* Select only if we have options */ | ||
609 | if ((dp & OMAP_DISPLAY_TYPE_VENC) && (dp & OMAP_DISPLAY_TYPE_HDMI)) | ||
610 | REG_FLD_MOD(DSS_CONTROL, src, 15, 15); /* VENC_HDMI_SWITCH */ | ||
654 | } | 611 | } |
655 | 612 | ||
656 | enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void) | 613 | enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void) |
@@ -661,9 +618,71 @@ enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void) | |||
661 | if ((displays & OMAP_DISPLAY_TYPE_HDMI) == 0) | 618 | if ((displays & OMAP_DISPLAY_TYPE_HDMI) == 0) |
662 | return DSS_VENC_TV_CLK; | 619 | return DSS_VENC_TV_CLK; |
663 | 620 | ||
621 | if ((displays & OMAP_DISPLAY_TYPE_VENC) == 0) | ||
622 | return DSS_HDMI_M_PCLK; | ||
623 | |||
664 | return REG_GET(DSS_CONTROL, 15, 15); | 624 | return REG_GET(DSS_CONTROL, 15, 15); |
665 | } | 625 | } |
666 | 626 | ||
627 | static int dss_dpi_select_source_omap2_omap3(enum omap_channel channel) | ||
628 | { | ||
629 | if (channel != OMAP_DSS_CHANNEL_LCD) | ||
630 | return -EINVAL; | ||
631 | |||
632 | return 0; | ||
633 | } | ||
634 | |||
635 | static int dss_dpi_select_source_omap4(enum omap_channel channel) | ||
636 | { | ||
637 | int val; | ||
638 | |||
639 | switch (channel) { | ||
640 | case OMAP_DSS_CHANNEL_LCD2: | ||
641 | val = 0; | ||
642 | break; | ||
643 | case OMAP_DSS_CHANNEL_DIGIT: | ||
644 | val = 1; | ||
645 | break; | ||
646 | default: | ||
647 | return -EINVAL; | ||
648 | } | ||
649 | |||
650 | REG_FLD_MOD(DSS_CONTROL, val, 17, 17); | ||
651 | |||
652 | return 0; | ||
653 | } | ||
654 | |||
655 | static int dss_dpi_select_source_omap5(enum omap_channel channel) | ||
656 | { | ||
657 | int val; | ||
658 | |||
659 | switch (channel) { | ||
660 | case OMAP_DSS_CHANNEL_LCD: | ||
661 | val = 1; | ||
662 | break; | ||
663 | case OMAP_DSS_CHANNEL_LCD2: | ||
664 | val = 2; | ||
665 | break; | ||
666 | case OMAP_DSS_CHANNEL_LCD3: | ||
667 | val = 3; | ||
668 | break; | ||
669 | case OMAP_DSS_CHANNEL_DIGIT: | ||
670 | val = 0; | ||
671 | break; | ||
672 | default: | ||
673 | return -EINVAL; | ||
674 | } | ||
675 | |||
676 | REG_FLD_MOD(DSS_CONTROL, val, 17, 16); | ||
677 | |||
678 | return 0; | ||
679 | } | ||
680 | |||
681 | int dss_dpi_select_source(enum omap_channel channel) | ||
682 | { | ||
683 | return dss.feat->dpi_select_source(channel); | ||
684 | } | ||
685 | |||
667 | static int dss_get_clocks(void) | 686 | static int dss_get_clocks(void) |
668 | { | 687 | { |
669 | struct clk *clk; | 688 | struct clk *clk; |
@@ -678,22 +697,11 @@ static int dss_get_clocks(void) | |||
678 | 697 | ||
679 | dss.dss_clk = clk; | 698 | dss.dss_clk = clk; |
680 | 699 | ||
681 | if (cpu_is_omap34xx()) { | 700 | clk = clk_get(NULL, dss.feat->clk_name); |
682 | clk = clk_get(NULL, "dpll4_m4_ck"); | 701 | if (IS_ERR(clk)) { |
683 | if (IS_ERR(clk)) { | 702 | DSSERR("Failed to get %s\n", dss.feat->clk_name); |
684 | DSSERR("Failed to get dpll4_m4_ck\n"); | 703 | r = PTR_ERR(clk); |
685 | r = PTR_ERR(clk); | 704 | goto err; |
686 | goto err; | ||
687 | } | ||
688 | } else if (cpu_is_omap44xx()) { | ||
689 | clk = clk_get(NULL, "dpll_per_m5x2_ck"); | ||
690 | if (IS_ERR(clk)) { | ||
691 | DSSERR("Failed to get dpll_per_m5x2_ck\n"); | ||
692 | r = PTR_ERR(clk); | ||
693 | goto err; | ||
694 | } | ||
695 | } else { /* omap24xx */ | ||
696 | clk = NULL; | ||
697 | } | 705 | } |
698 | 706 | ||
699 | dss.dpll4_m4_ck = clk; | 707 | dss.dpll4_m4_ck = clk; |
@@ -749,6 +757,71 @@ void dss_debug_dump_clocks(struct seq_file *s) | |||
749 | } | 757 | } |
750 | #endif | 758 | #endif |
751 | 759 | ||
760 | static const struct dss_features omap24xx_dss_feats __initconst = { | ||
761 | .fck_div_max = 16, | ||
762 | .dss_fck_multiplier = 2, | ||
763 | .clk_name = NULL, | ||
764 | .dpi_select_source = &dss_dpi_select_source_omap2_omap3, | ||
765 | }; | ||
766 | |||
767 | static const struct dss_features omap34xx_dss_feats __initconst = { | ||
768 | .fck_div_max = 16, | ||
769 | .dss_fck_multiplier = 2, | ||
770 | .clk_name = "dpll4_m4_ck", | ||
771 | .dpi_select_source = &dss_dpi_select_source_omap2_omap3, | ||
772 | }; | ||
773 | |||
774 | static const struct dss_features omap3630_dss_feats __initconst = { | ||
775 | .fck_div_max = 32, | ||
776 | .dss_fck_multiplier = 1, | ||
777 | .clk_name = "dpll4_m4_ck", | ||
778 | .dpi_select_source = &dss_dpi_select_source_omap2_omap3, | ||
779 | }; | ||
780 | |||
781 | static const struct dss_features omap44xx_dss_feats __initconst = { | ||
782 | .fck_div_max = 32, | ||
783 | .dss_fck_multiplier = 1, | ||
784 | .clk_name = "dpll_per_m5x2_ck", | ||
785 | .dpi_select_source = &dss_dpi_select_source_omap4, | ||
786 | }; | ||
787 | |||
788 | static const struct dss_features omap54xx_dss_feats __initconst = { | ||
789 | .fck_div_max = 64, | ||
790 | .dss_fck_multiplier = 1, | ||
791 | .clk_name = "dpll_per_h12x2_ck", | ||
792 | .dpi_select_source = &dss_dpi_select_source_omap5, | ||
793 | }; | ||
794 | |||
795 | static int __init dss_init_features(struct device *dev) | ||
796 | { | ||
797 | const struct dss_features *src; | ||
798 | struct dss_features *dst; | ||
799 | |||
800 | dst = devm_kzalloc(dev, sizeof(*dst), GFP_KERNEL); | ||
801 | if (!dst) { | ||
802 | dev_err(dev, "Failed to allocate local DSS Features\n"); | ||
803 | return -ENOMEM; | ||
804 | } | ||
805 | |||
806 | if (cpu_is_omap24xx()) | ||
807 | src = &omap24xx_dss_feats; | ||
808 | else if (cpu_is_omap34xx()) | ||
809 | src = &omap34xx_dss_feats; | ||
810 | else if (cpu_is_omap3630()) | ||
811 | src = &omap3630_dss_feats; | ||
812 | else if (cpu_is_omap44xx()) | ||
813 | src = &omap44xx_dss_feats; | ||
814 | else if (soc_is_omap54xx()) | ||
815 | src = &omap54xx_dss_feats; | ||
816 | else | ||
817 | return -ENODEV; | ||
818 | |||
819 | memcpy(dst, src, sizeof(*dst)); | ||
820 | dss.feat = dst; | ||
821 | |||
822 | return 0; | ||
823 | } | ||
824 | |||
752 | /* DSS HW IP initialisation */ | 825 | /* DSS HW IP initialisation */ |
753 | static int __init omap_dsshw_probe(struct platform_device *pdev) | 826 | static int __init omap_dsshw_probe(struct platform_device *pdev) |
754 | { | 827 | { |
@@ -758,6 +831,10 @@ static int __init omap_dsshw_probe(struct platform_device *pdev) | |||
758 | 831 | ||
759 | dss.pdev = pdev; | 832 | dss.pdev = pdev; |
760 | 833 | ||
834 | r = dss_init_features(&dss.pdev->dev); | ||
835 | if (r) | ||
836 | return r; | ||
837 | |||
761 | dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0); | 838 | dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0); |
762 | if (!dss_mem) { | 839 | if (!dss_mem) { |
763 | DSSERR("can't get IORESOURCE_MEM DSS\n"); | 840 | DSSERR("can't get IORESOURCE_MEM DSS\n"); |
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index f67afe76f217..6728892f9dad 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h | |||
@@ -113,6 +113,17 @@ enum dss_dsi_content_type { | |||
113 | DSS_DSI_CONTENT_GENERIC, | 113 | DSS_DSI_CONTENT_GENERIC, |
114 | }; | 114 | }; |
115 | 115 | ||
116 | enum dss_writeback_channel { | ||
117 | DSS_WB_LCD1_MGR = 0, | ||
118 | DSS_WB_LCD2_MGR = 1, | ||
119 | DSS_WB_TV_MGR = 2, | ||
120 | DSS_WB_OVL0 = 3, | ||
121 | DSS_WB_OVL1 = 4, | ||
122 | DSS_WB_OVL2 = 5, | ||
123 | DSS_WB_OVL3 = 6, | ||
124 | DSS_WB_LCD3_MGR = 7, | ||
125 | }; | ||
126 | |||
116 | struct dss_clock_info { | 127 | struct dss_clock_info { |
117 | /* rates that we get with dividers below */ | 128 | /* rates that we get with dividers below */ |
118 | unsigned long fck; | 129 | unsigned long fck; |
@@ -175,6 +186,7 @@ struct seq_file; | |||
175 | struct platform_device; | 186 | struct platform_device; |
176 | 187 | ||
177 | /* core */ | 188 | /* core */ |
189 | const char *dss_get_default_display_name(void); | ||
178 | struct bus_type *dss_get_bus(void); | 190 | struct bus_type *dss_get_bus(void); |
179 | struct regulator *dss_get_vdds_dsi(void); | 191 | struct regulator *dss_get_vdds_dsi(void); |
180 | struct regulator *dss_get_vdds_sdi(void); | 192 | struct regulator *dss_get_vdds_sdi(void); |
@@ -184,10 +196,13 @@ void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask); | |||
184 | int dss_set_min_bus_tput(struct device *dev, unsigned long tput); | 196 | int dss_set_min_bus_tput(struct device *dev, unsigned long tput); |
185 | int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)); | 197 | int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)); |
186 | 198 | ||
187 | int omap_dss_register_device(struct omap_dss_device *dssdev, | 199 | struct omap_dss_device *dss_alloc_and_init_device(struct device *parent); |
188 | struct device *parent, int disp_num); | 200 | int dss_add_device(struct omap_dss_device *dssdev); |
189 | void omap_dss_unregister_device(struct omap_dss_device *dssdev); | 201 | void dss_unregister_device(struct omap_dss_device *dssdev); |
190 | void omap_dss_unregister_child_devices(struct device *parent); | 202 | void dss_unregister_child_devices(struct device *parent); |
203 | void dss_put_device(struct omap_dss_device *dssdev); | ||
204 | void dss_copy_device_pdata(struct omap_dss_device *dst, | ||
205 | const struct omap_dss_device *src); | ||
191 | 206 | ||
192 | /* apply */ | 207 | /* apply */ |
193 | void dss_apply_init(void); | 208 | void dss_apply_init(void); |
@@ -205,8 +220,11 @@ void dss_mgr_get_info(struct omap_overlay_manager *mgr, | |||
205 | int dss_mgr_set_device(struct omap_overlay_manager *mgr, | 220 | int dss_mgr_set_device(struct omap_overlay_manager *mgr, |
206 | struct omap_dss_device *dssdev); | 221 | struct omap_dss_device *dssdev); |
207 | int dss_mgr_unset_device(struct omap_overlay_manager *mgr); | 222 | int dss_mgr_unset_device(struct omap_overlay_manager *mgr); |
223 | int dss_mgr_set_output(struct omap_overlay_manager *mgr, | ||
224 | struct omap_dss_output *output); | ||
225 | int dss_mgr_unset_output(struct omap_overlay_manager *mgr); | ||
208 | void dss_mgr_set_timings(struct omap_overlay_manager *mgr, | 226 | void dss_mgr_set_timings(struct omap_overlay_manager *mgr, |
209 | struct omap_video_timings *timings); | 227 | const struct omap_video_timings *timings); |
210 | void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr, | 228 | void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr, |
211 | const struct dss_lcd_mgr_config *config); | 229 | const struct dss_lcd_mgr_config *config); |
212 | const struct omap_video_timings *dss_mgr_get_timings(struct omap_overlay_manager *mgr); | 230 | const struct omap_video_timings *dss_mgr_get_timings(struct omap_overlay_manager *mgr); |
@@ -222,12 +240,17 @@ int dss_ovl_set_manager(struct omap_overlay *ovl, | |||
222 | struct omap_overlay_manager *mgr); | 240 | struct omap_overlay_manager *mgr); |
223 | int dss_ovl_unset_manager(struct omap_overlay *ovl); | 241 | int dss_ovl_unset_manager(struct omap_overlay *ovl); |
224 | 242 | ||
243 | /* output */ | ||
244 | void dss_register_output(struct omap_dss_output *out); | ||
245 | void dss_unregister_output(struct omap_dss_output *out); | ||
246 | struct omap_dss_output *omapdss_get_output_from_dssdev(struct omap_dss_device *dssdev); | ||
247 | |||
225 | /* display */ | 248 | /* display */ |
226 | int dss_suspend_all_devices(void); | 249 | int dss_suspend_all_devices(void); |
227 | int dss_resume_all_devices(void); | 250 | int dss_resume_all_devices(void); |
228 | void dss_disable_all_devices(void); | 251 | void dss_disable_all_devices(void); |
229 | 252 | ||
230 | void dss_init_device(struct platform_device *pdev, | 253 | int dss_init_device(struct platform_device *pdev, |
231 | struct omap_dss_device *dssdev); | 254 | struct omap_dss_device *dssdev); |
232 | void dss_uninit_device(struct platform_device *pdev, | 255 | void dss_uninit_device(struct platform_device *pdev, |
233 | struct omap_dss_device *dssdev); | 256 | struct omap_dss_device *dssdev); |
@@ -254,22 +277,29 @@ static inline bool dss_mgr_is_lcd(enum omap_channel id) | |||
254 | return false; | 277 | return false; |
255 | } | 278 | } |
256 | 279 | ||
280 | int dss_manager_kobj_init(struct omap_overlay_manager *mgr, | ||
281 | struct platform_device *pdev); | ||
282 | void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr); | ||
283 | |||
257 | /* overlay */ | 284 | /* overlay */ |
258 | void dss_init_overlays(struct platform_device *pdev); | 285 | void dss_init_overlays(struct platform_device *pdev); |
259 | void dss_uninit_overlays(struct platform_device *pdev); | 286 | void dss_uninit_overlays(struct platform_device *pdev); |
260 | void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr); | 287 | void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr); |
261 | void dss_recheck_connections(struct omap_dss_device *dssdev, bool force); | ||
262 | int dss_ovl_simple_check(struct omap_overlay *ovl, | 288 | int dss_ovl_simple_check(struct omap_overlay *ovl, |
263 | const struct omap_overlay_info *info); | 289 | const struct omap_overlay_info *info); |
264 | int dss_ovl_check(struct omap_overlay *ovl, struct omap_overlay_info *info, | 290 | int dss_ovl_check(struct omap_overlay *ovl, struct omap_overlay_info *info, |
265 | const struct omap_video_timings *mgr_timings); | 291 | const struct omap_video_timings *mgr_timings); |
266 | bool dss_ovl_use_replication(struct dss_lcd_mgr_config config, | 292 | bool dss_ovl_use_replication(struct dss_lcd_mgr_config config, |
267 | enum omap_color_mode mode); | 293 | enum omap_color_mode mode); |
294 | int dss_overlay_kobj_init(struct omap_overlay *ovl, | ||
295 | struct platform_device *pdev); | ||
296 | void dss_overlay_kobj_uninit(struct omap_overlay *ovl); | ||
268 | 297 | ||
269 | /* DSS */ | 298 | /* DSS */ |
270 | int dss_init_platform_driver(void) __init; | 299 | int dss_init_platform_driver(void) __init; |
271 | void dss_uninit_platform_driver(void); | 300 | void dss_uninit_platform_driver(void); |
272 | 301 | ||
302 | int dss_dpi_select_source(enum omap_channel channel); | ||
273 | void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select); | 303 | void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select); |
274 | enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void); | 304 | enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void); |
275 | const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src); | 305 | const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src); |
@@ -279,7 +309,7 @@ void dss_dump_clocks(struct seq_file *s); | |||
279 | void dss_debug_dump_clocks(struct seq_file *s); | 309 | void dss_debug_dump_clocks(struct seq_file *s); |
280 | #endif | 310 | #endif |
281 | 311 | ||
282 | void dss_sdi_init(u8 datapairs); | 312 | void dss_sdi_init(int datapairs); |
283 | int dss_sdi_enable(void); | 313 | int dss_sdi_enable(void); |
284 | void dss_sdi_disable(void); | 314 | void dss_sdi_disable(void); |
285 | 315 | ||
@@ -296,9 +326,7 @@ void dss_set_venc_output(enum omap_dss_venc_type type); | |||
296 | void dss_set_dac_pwrdn_bgz(bool enable); | 326 | void dss_set_dac_pwrdn_bgz(bool enable); |
297 | 327 | ||
298 | unsigned long dss_get_dpll4_rate(void); | 328 | unsigned long dss_get_dpll4_rate(void); |
299 | int dss_calc_clock_rates(struct dss_clock_info *cinfo); | ||
300 | int dss_set_clock_div(struct dss_clock_info *cinfo); | 329 | int dss_set_clock_div(struct dss_clock_info *cinfo); |
301 | int dss_get_clock_div(struct dss_clock_info *cinfo); | ||
302 | int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo, | 330 | int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo, |
303 | struct dispc_clock_info *dispc_cinfo); | 331 | struct dispc_clock_info *dispc_cinfo); |
304 | 332 | ||
@@ -427,8 +455,9 @@ void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high); | |||
427 | void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane, | 455 | void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane, |
428 | u32 *fifo_low, u32 *fifo_high, bool use_fifomerge, | 456 | u32 *fifo_low, u32 *fifo_high, bool use_fifomerge, |
429 | bool manual_update); | 457 | bool manual_update); |
430 | int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, | 458 | int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi, |
431 | bool replication, const struct omap_video_timings *mgr_timings); | 459 | bool replication, const struct omap_video_timings *mgr_timings, |
460 | bool mem_to_mem); | ||
432 | int dispc_ovl_enable(enum omap_plane plane, bool enable); | 461 | int dispc_ovl_enable(enum omap_plane plane, bool enable); |
433 | void dispc_ovl_set_channel_out(enum omap_plane plane, | 462 | void dispc_ovl_set_channel_out(enum omap_plane plane, |
434 | enum omap_channel channel); | 463 | enum omap_channel channel); |
@@ -457,6 +486,15 @@ int dispc_mgr_get_clock_div(enum omap_channel channel, | |||
457 | void dispc_mgr_setup(enum omap_channel channel, | 486 | void dispc_mgr_setup(enum omap_channel channel, |
458 | struct omap_overlay_manager_info *info); | 487 | struct omap_overlay_manager_info *info); |
459 | 488 | ||
489 | u32 dispc_wb_get_framedone_irq(void); | ||
490 | bool dispc_wb_go_busy(void); | ||
491 | void dispc_wb_go(void); | ||
492 | void dispc_wb_enable(bool enable); | ||
493 | bool dispc_wb_is_enabled(void); | ||
494 | void dispc_wb_set_channel_in(enum dss_writeback_channel channel); | ||
495 | int dispc_wb_setup(const struct omap_dss_writeback_info *wi, | ||
496 | bool mem_to_mem, const struct omap_video_timings *timings); | ||
497 | |||
460 | /* VENC */ | 498 | /* VENC */ |
461 | #ifdef CONFIG_OMAP2_DSS_VENC | 499 | #ifdef CONFIG_OMAP2_DSS_VENC |
462 | int venc_init_platform_driver(void) __init; | 500 | int venc_init_platform_driver(void) __init; |
@@ -469,6 +507,20 @@ static inline unsigned long venc_get_pixel_clock(void) | |||
469 | return 0; | 507 | return 0; |
470 | } | 508 | } |
471 | #endif | 509 | #endif |
510 | int omapdss_venc_display_enable(struct omap_dss_device *dssdev); | ||
511 | void omapdss_venc_display_disable(struct omap_dss_device *dssdev); | ||
512 | void omapdss_venc_set_timings(struct omap_dss_device *dssdev, | ||
513 | struct omap_video_timings *timings); | ||
514 | int omapdss_venc_check_timings(struct omap_dss_device *dssdev, | ||
515 | struct omap_video_timings *timings); | ||
516 | u32 omapdss_venc_get_wss(struct omap_dss_device *dssdev); | ||
517 | int omapdss_venc_set_wss(struct omap_dss_device *dssdev, u32 wss); | ||
518 | void omapdss_venc_set_type(struct omap_dss_device *dssdev, | ||
519 | enum omap_dss_venc_type type); | ||
520 | void omapdss_venc_invert_vid_out_polarity(struct omap_dss_device *dssdev, | ||
521 | bool invert_polarity); | ||
522 | int venc_panel_init(void); | ||
523 | void venc_panel_exit(void); | ||
472 | 524 | ||
473 | /* HDMI */ | 525 | /* HDMI */ |
474 | #ifdef CONFIG_OMAP4_DSS_HDMI | 526 | #ifdef CONFIG_OMAP4_DSS_HDMI |
@@ -484,7 +536,8 @@ static inline unsigned long hdmi_get_pixel_clock(void) | |||
484 | #endif | 536 | #endif |
485 | int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev); | 537 | int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev); |
486 | void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev); | 538 | void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev); |
487 | void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev); | 539 | void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev, |
540 | struct omap_video_timings *timings); | ||
488 | int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, | 541 | int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, |
489 | struct omap_video_timings *timings); | 542 | struct omap_video_timings *timings); |
490 | int omapdss_hdmi_read_edid(u8 *buf, int len); | 543 | int omapdss_hdmi_read_edid(u8 *buf, int len); |
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index 938709724f0c..acbc1e1efba3 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c | |||
@@ -46,7 +46,9 @@ struct omap_dss_features { | |||
46 | 46 | ||
47 | const int num_mgrs; | 47 | const int num_mgrs; |
48 | const int num_ovls; | 48 | const int num_ovls; |
49 | const int num_wbs; | ||
49 | const enum omap_display_type *supported_displays; | 50 | const enum omap_display_type *supported_displays; |
51 | const enum omap_dss_output_id *supported_outputs; | ||
50 | const enum omap_color_mode *supported_color_modes; | 52 | const enum omap_color_mode *supported_color_modes; |
51 | const enum omap_overlay_caps *overlay_caps; | 53 | const enum omap_overlay_caps *overlay_caps; |
52 | const char * const *clksrc_names; | 54 | const char * const *clksrc_names; |
@@ -106,6 +108,21 @@ static const struct dss_reg_field omap4_dss_reg_fields[] = { | |||
106 | [FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 }, | 108 | [FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 }, |
107 | }; | 109 | }; |
108 | 110 | ||
111 | static const struct dss_reg_field omap5_dss_reg_fields[] = { | ||
112 | [FEAT_REG_FIRHINC] = { 12, 0 }, | ||
113 | [FEAT_REG_FIRVINC] = { 28, 16 }, | ||
114 | [FEAT_REG_FIFOLOWTHRESHOLD] = { 15, 0 }, | ||
115 | [FEAT_REG_FIFOHIGHTHRESHOLD] = { 31, 16 }, | ||
116 | [FEAT_REG_FIFOSIZE] = { 15, 0 }, | ||
117 | [FEAT_REG_HORIZONTALACCU] = { 10, 0 }, | ||
118 | [FEAT_REG_VERTICALACCU] = { 26, 16 }, | ||
119 | [FEAT_REG_DISPC_CLK_SWITCH] = { 9, 7 }, | ||
120 | [FEAT_REG_DSIPLL_REGN] = { 8, 1 }, | ||
121 | [FEAT_REG_DSIPLL_REGM] = { 20, 9 }, | ||
122 | [FEAT_REG_DSIPLL_REGM_DISPC] = { 25, 21 }, | ||
123 | [FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 }, | ||
124 | }; | ||
125 | |||
109 | static const enum omap_display_type omap2_dss_supported_displays[] = { | 126 | static const enum omap_display_type omap2_dss_supported_displays[] = { |
110 | /* OMAP_DSS_CHANNEL_LCD */ | 127 | /* OMAP_DSS_CHANNEL_LCD */ |
111 | OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI, | 128 | OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI, |
@@ -144,6 +161,76 @@ static const enum omap_display_type omap4_dss_supported_displays[] = { | |||
144 | OMAP_DISPLAY_TYPE_DSI, | 161 | OMAP_DISPLAY_TYPE_DSI, |
145 | }; | 162 | }; |
146 | 163 | ||
164 | static const enum omap_display_type omap5_dss_supported_displays[] = { | ||
165 | /* OMAP_DSS_CHANNEL_LCD */ | ||
166 | OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI | | ||
167 | OMAP_DISPLAY_TYPE_DSI, | ||
168 | |||
169 | /* OMAP_DSS_CHANNEL_DIGIT */ | ||
170 | OMAP_DISPLAY_TYPE_HDMI | OMAP_DISPLAY_TYPE_DPI, | ||
171 | |||
172 | /* OMAP_DSS_CHANNEL_LCD2 */ | ||
173 | OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI | | ||
174 | OMAP_DISPLAY_TYPE_DSI, | ||
175 | }; | ||
176 | |||
177 | static const enum omap_dss_output_id omap2_dss_supported_outputs[] = { | ||
178 | /* OMAP_DSS_CHANNEL_LCD */ | ||
179 | OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI, | ||
180 | |||
181 | /* OMAP_DSS_CHANNEL_DIGIT */ | ||
182 | OMAP_DSS_OUTPUT_VENC, | ||
183 | }; | ||
184 | |||
185 | static const enum omap_dss_output_id omap3430_dss_supported_outputs[] = { | ||
186 | /* OMAP_DSS_CHANNEL_LCD */ | ||
187 | OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | | ||
188 | OMAP_DSS_OUTPUT_SDI | OMAP_DSS_OUTPUT_DSI1, | ||
189 | |||
190 | /* OMAP_DSS_CHANNEL_DIGIT */ | ||
191 | OMAP_DSS_OUTPUT_VENC, | ||
192 | }; | ||
193 | |||
194 | static const enum omap_dss_output_id omap3630_dss_supported_outputs[] = { | ||
195 | /* OMAP_DSS_CHANNEL_LCD */ | ||
196 | OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | | ||
197 | OMAP_DSS_OUTPUT_DSI1, | ||
198 | |||
199 | /* OMAP_DSS_CHANNEL_DIGIT */ | ||
200 | OMAP_DSS_OUTPUT_VENC, | ||
201 | }; | ||
202 | |||
203 | static const enum omap_dss_output_id omap4_dss_supported_outputs[] = { | ||
204 | /* OMAP_DSS_CHANNEL_LCD */ | ||
205 | OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | | ||
206 | OMAP_DSS_OUTPUT_DSI1, | ||
207 | |||
208 | /* OMAP_DSS_CHANNEL_DIGIT */ | ||
209 | OMAP_DSS_OUTPUT_VENC | OMAP_DSS_OUTPUT_HDMI | | ||
210 | OMAP_DSS_OUTPUT_DPI, | ||
211 | |||
212 | /* OMAP_DSS_CHANNEL_LCD2 */ | ||
213 | OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | | ||
214 | OMAP_DSS_OUTPUT_DSI2, | ||
215 | }; | ||
216 | |||
217 | static const enum omap_dss_output_id omap5_dss_supported_outputs[] = { | ||
218 | /* OMAP_DSS_CHANNEL_LCD */ | ||
219 | OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | | ||
220 | OMAP_DSS_OUTPUT_DSI1 | OMAP_DSS_OUTPUT_DSI2, | ||
221 | |||
222 | /* OMAP_DSS_CHANNEL_DIGIT */ | ||
223 | OMAP_DSS_OUTPUT_HDMI | OMAP_DSS_OUTPUT_DPI, | ||
224 | |||
225 | /* OMAP_DSS_CHANNEL_LCD2 */ | ||
226 | OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | | ||
227 | OMAP_DSS_OUTPUT_DSI1, | ||
228 | |||
229 | /* OMAP_DSS_CHANNEL_LCD3 */ | ||
230 | OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | | ||
231 | OMAP_DSS_OUTPUT_DSI2, | ||
232 | }; | ||
233 | |||
147 | static const enum omap_color_mode omap2_dss_supported_color_modes[] = { | 234 | static const enum omap_color_mode omap2_dss_supported_color_modes[] = { |
148 | /* OMAP_DSS_GFX */ | 235 | /* OMAP_DSS_GFX */ |
149 | OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 | | 236 | OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 | |
@@ -224,58 +311,80 @@ static const enum omap_color_mode omap4_dss_supported_color_modes[] = { | |||
224 | OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 | | 311 | OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 | |
225 | OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 | | 312 | OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 | |
226 | OMAP_DSS_COLOR_RGBX32, | 313 | OMAP_DSS_COLOR_RGBX32, |
314 | |||
315 | /* OMAP_DSS_WB */ | ||
316 | OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U | | ||
317 | OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_ARGB16_1555 | | ||
318 | OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_NV12 | | ||
319 | OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_RGB24U | | ||
320 | OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_UYVY | | ||
321 | OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 | | ||
322 | OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 | | ||
323 | OMAP_DSS_COLOR_RGBX32, | ||
227 | }; | 324 | }; |
228 | 325 | ||
229 | static const enum omap_overlay_caps omap2_dss_overlay_caps[] = { | 326 | static const enum omap_overlay_caps omap2_dss_overlay_caps[] = { |
230 | /* OMAP_DSS_GFX */ | 327 | /* OMAP_DSS_GFX */ |
231 | 0, | 328 | OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, |
232 | 329 | ||
233 | /* OMAP_DSS_VIDEO1 */ | 330 | /* OMAP_DSS_VIDEO1 */ |
234 | OMAP_DSS_OVL_CAP_SCALE, | 331 | OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS | |
332 | OMAP_DSS_OVL_CAP_REPLICATION, | ||
235 | 333 | ||
236 | /* OMAP_DSS_VIDEO2 */ | 334 | /* OMAP_DSS_VIDEO2 */ |
237 | OMAP_DSS_OVL_CAP_SCALE, | 335 | OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS | |
336 | OMAP_DSS_OVL_CAP_REPLICATION, | ||
238 | }; | 337 | }; |
239 | 338 | ||
240 | static const enum omap_overlay_caps omap3430_dss_overlay_caps[] = { | 339 | static const enum omap_overlay_caps omap3430_dss_overlay_caps[] = { |
241 | /* OMAP_DSS_GFX */ | 340 | /* OMAP_DSS_GFX */ |
242 | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA, | 341 | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_POS | |
342 | OMAP_DSS_OVL_CAP_REPLICATION, | ||
243 | 343 | ||
244 | /* OMAP_DSS_VIDEO1 */ | 344 | /* OMAP_DSS_VIDEO1 */ |
245 | OMAP_DSS_OVL_CAP_SCALE, | 345 | OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS | |
346 | OMAP_DSS_OVL_CAP_REPLICATION, | ||
246 | 347 | ||
247 | /* OMAP_DSS_VIDEO2 */ | 348 | /* OMAP_DSS_VIDEO2 */ |
248 | OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA, | 349 | OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | |
350 | OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, | ||
249 | }; | 351 | }; |
250 | 352 | ||
251 | static const enum omap_overlay_caps omap3630_dss_overlay_caps[] = { | 353 | static const enum omap_overlay_caps omap3630_dss_overlay_caps[] = { |
252 | /* OMAP_DSS_GFX */ | 354 | /* OMAP_DSS_GFX */ |
253 | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA, | 355 | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | |
356 | OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, | ||
254 | 357 | ||
255 | /* OMAP_DSS_VIDEO1 */ | 358 | /* OMAP_DSS_VIDEO1 */ |
256 | OMAP_DSS_OVL_CAP_SCALE, | 359 | OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS | |
360 | OMAP_DSS_OVL_CAP_REPLICATION, | ||
257 | 361 | ||
258 | /* OMAP_DSS_VIDEO2 */ | 362 | /* OMAP_DSS_VIDEO2 */ |
259 | OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | | 363 | OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | |
260 | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA, | 364 | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_POS | |
365 | OMAP_DSS_OVL_CAP_REPLICATION, | ||
261 | }; | 366 | }; |
262 | 367 | ||
263 | static const enum omap_overlay_caps omap4_dss_overlay_caps[] = { | 368 | static const enum omap_overlay_caps omap4_dss_overlay_caps[] = { |
264 | /* OMAP_DSS_GFX */ | 369 | /* OMAP_DSS_GFX */ |
265 | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | | 370 | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | |
266 | OMAP_DSS_OVL_CAP_ZORDER, | 371 | OMAP_DSS_OVL_CAP_ZORDER | OMAP_DSS_OVL_CAP_POS | |
372 | OMAP_DSS_OVL_CAP_REPLICATION, | ||
267 | 373 | ||
268 | /* OMAP_DSS_VIDEO1 */ | 374 | /* OMAP_DSS_VIDEO1 */ |
269 | OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | | 375 | OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | |
270 | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER, | 376 | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER | |
377 | OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, | ||
271 | 378 | ||
272 | /* OMAP_DSS_VIDEO2 */ | 379 | /* OMAP_DSS_VIDEO2 */ |
273 | OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | | 380 | OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | |
274 | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER, | 381 | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER | |
382 | OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, | ||
275 | 383 | ||
276 | /* OMAP_DSS_VIDEO3 */ | 384 | /* OMAP_DSS_VIDEO3 */ |
277 | OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | | 385 | OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | |
278 | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER, | 386 | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER | |
387 | OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, | ||
279 | }; | 388 | }; |
280 | 389 | ||
281 | static const char * const omap2_dss_clk_source_names[] = { | 390 | static const char * const omap2_dss_clk_source_names[] = { |
@@ -298,6 +407,14 @@ static const char * const omap4_dss_clk_source_names[] = { | |||
298 | [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "PLL2_CLK2", | 407 | [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "PLL2_CLK2", |
299 | }; | 408 | }; |
300 | 409 | ||
410 | static const char * const omap5_dss_clk_source_names[] = { | ||
411 | [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DPLL_DSI1_A_CLK1", | ||
412 | [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DPLL_DSI1_A_CLK2", | ||
413 | [OMAP_DSS_CLK_SRC_FCK] = "DSS_CLK", | ||
414 | [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC] = "DPLL_DSI1_C_CLK1", | ||
415 | [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "DPLL_DSI1_C_CLK2", | ||
416 | }; | ||
417 | |||
301 | static const struct dss_param_range omap2_dss_param_range[] = { | 418 | static const struct dss_param_range omap2_dss_param_range[] = { |
302 | [FEAT_PARAM_DSS_FCK] = { 0, 173000000 }, | 419 | [FEAT_PARAM_DSS_FCK] = { 0, 173000000 }, |
303 | [FEAT_PARAM_DSS_PCD] = { 2, 255 }, | 420 | [FEAT_PARAM_DSS_PCD] = { 2, 255 }, |
@@ -326,6 +443,7 @@ static const struct dss_param_range omap3_dss_param_range[] = { | |||
326 | [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 4) - 1 }, | 443 | [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 4) - 1 }, |
327 | [FEAT_PARAM_DSIPLL_FINT] = { 750000, 2100000 }, | 444 | [FEAT_PARAM_DSIPLL_FINT] = { 750000, 2100000 }, |
328 | [FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1}, | 445 | [FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1}, |
446 | [FEAT_PARAM_DSI_FCK] = { 0, 173000000 }, | ||
329 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, | 447 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, |
330 | [FEAT_PARAM_LINEWIDTH] = { 1, 1024 }, | 448 | [FEAT_PARAM_LINEWIDTH] = { 1, 1024 }, |
331 | [FEAT_PARAM_MGR_WIDTH] = { 1, 2048 }, | 449 | [FEAT_PARAM_MGR_WIDTH] = { 1, 2048 }, |
@@ -341,6 +459,23 @@ static const struct dss_param_range omap4_dss_param_range[] = { | |||
341 | [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 }, | 459 | [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 }, |
342 | [FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 }, | 460 | [FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 }, |
343 | [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 }, | 461 | [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 }, |
462 | [FEAT_PARAM_DSI_FCK] = { 0, 170000000 }, | ||
463 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, | ||
464 | [FEAT_PARAM_LINEWIDTH] = { 1, 2048 }, | ||
465 | [FEAT_PARAM_MGR_WIDTH] = { 1, 2048 }, | ||
466 | [FEAT_PARAM_MGR_HEIGHT] = { 1, 2048 }, | ||
467 | }; | ||
468 | |||
469 | static const struct dss_param_range omap5_dss_param_range[] = { | ||
470 | [FEAT_PARAM_DSS_FCK] = { 0, 200000000 }, | ||
471 | [FEAT_PARAM_DSS_PCD] = { 1, 255 }, | ||
472 | [FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 8) - 1 }, | ||
473 | [FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 12) - 1 }, | ||
474 | [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 5) - 1 }, | ||
475 | [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 }, | ||
476 | [FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 }, | ||
477 | [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 }, | ||
478 | [FEAT_PARAM_DSI_FCK] = { 0, 170000000 }, | ||
344 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, | 479 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, |
345 | [FEAT_PARAM_LINEWIDTH] = { 1, 2048 }, | 480 | [FEAT_PARAM_LINEWIDTH] = { 1, 2048 }, |
346 | [FEAT_PARAM_MGR_WIDTH] = { 1, 2048 }, | 481 | [FEAT_PARAM_MGR_WIDTH] = { 1, 2048 }, |
@@ -373,6 +508,26 @@ static const enum dss_feat_id omap3430_dss_feat_list[] = { | |||
373 | FEAT_ALPHA_FIXED_ZORDER, | 508 | FEAT_ALPHA_FIXED_ZORDER, |
374 | FEAT_FIFO_MERGE, | 509 | FEAT_FIFO_MERGE, |
375 | FEAT_OMAP3_DSI_FIFO_BUG, | 510 | FEAT_OMAP3_DSI_FIFO_BUG, |
511 | FEAT_DPI_USES_VDDS_DSI, | ||
512 | }; | ||
513 | |||
514 | static const enum dss_feat_id am35xx_dss_feat_list[] = { | ||
515 | FEAT_LCDENABLEPOL, | ||
516 | FEAT_LCDENABLESIGNAL, | ||
517 | FEAT_PCKFREEENABLE, | ||
518 | FEAT_FUNCGATED, | ||
519 | FEAT_LINEBUFFERSPLIT, | ||
520 | FEAT_ROWREPEATENABLE, | ||
521 | FEAT_RESIZECONF, | ||
522 | FEAT_DSI_PLL_FREQSEL, | ||
523 | FEAT_DSI_REVERSE_TXCLKESC, | ||
524 | FEAT_VENC_REQUIRES_TV_DAC_CLK, | ||
525 | FEAT_CPR, | ||
526 | FEAT_PRELOAD, | ||
527 | FEAT_FIR_COEF_V, | ||
528 | FEAT_ALPHA_FIXED_ZORDER, | ||
529 | FEAT_FIFO_MERGE, | ||
530 | FEAT_OMAP3_DSI_FIFO_BUG, | ||
376 | }; | 531 | }; |
377 | 532 | ||
378 | static const enum dss_feat_id omap3630_dss_feat_list[] = { | 533 | static const enum dss_feat_id omap3630_dss_feat_list[] = { |
@@ -447,6 +602,28 @@ static const enum dss_feat_id omap4_dss_feat_list[] = { | |||
447 | FEAT_BURST_2D, | 602 | FEAT_BURST_2D, |
448 | }; | 603 | }; |
449 | 604 | ||
605 | static const enum dss_feat_id omap5_dss_feat_list[] = { | ||
606 | FEAT_MGR_LCD2, | ||
607 | FEAT_CORE_CLK_DIV, | ||
608 | FEAT_LCD_CLK_SRC, | ||
609 | FEAT_DSI_DCS_CMD_CONFIG_VC, | ||
610 | FEAT_DSI_VC_OCP_WIDTH, | ||
611 | FEAT_DSI_GNQ, | ||
612 | FEAT_HDMI_CTS_SWMODE, | ||
613 | FEAT_HDMI_AUDIO_USE_MCLK, | ||
614 | FEAT_HANDLE_UV_SEPARATE, | ||
615 | FEAT_ATTR2, | ||
616 | FEAT_CPR, | ||
617 | FEAT_PRELOAD, | ||
618 | FEAT_FIR_COEF_V, | ||
619 | FEAT_ALPHA_FREE_ZORDER, | ||
620 | FEAT_FIFO_MERGE, | ||
621 | FEAT_BURST_2D, | ||
622 | FEAT_DSI_PLL_SELFREQDCO, | ||
623 | FEAT_DSI_PLL_REFSEL, | ||
624 | FEAT_DSI_PHY_DCC, | ||
625 | }; | ||
626 | |||
450 | /* OMAP2 DSS Features */ | 627 | /* OMAP2 DSS Features */ |
451 | static const struct omap_dss_features omap2_dss_features = { | 628 | static const struct omap_dss_features omap2_dss_features = { |
452 | .reg_fields = omap2_dss_reg_fields, | 629 | .reg_fields = omap2_dss_reg_fields, |
@@ -458,6 +635,7 @@ static const struct omap_dss_features omap2_dss_features = { | |||
458 | .num_mgrs = 2, | 635 | .num_mgrs = 2, |
459 | .num_ovls = 3, | 636 | .num_ovls = 3, |
460 | .supported_displays = omap2_dss_supported_displays, | 637 | .supported_displays = omap2_dss_supported_displays, |
638 | .supported_outputs = omap2_dss_supported_outputs, | ||
461 | .supported_color_modes = omap2_dss_supported_color_modes, | 639 | .supported_color_modes = omap2_dss_supported_color_modes, |
462 | .overlay_caps = omap2_dss_overlay_caps, | 640 | .overlay_caps = omap2_dss_overlay_caps, |
463 | .clksrc_names = omap2_dss_clk_source_names, | 641 | .clksrc_names = omap2_dss_clk_source_names, |
@@ -478,6 +656,31 @@ static const struct omap_dss_features omap3430_dss_features = { | |||
478 | .num_mgrs = 2, | 656 | .num_mgrs = 2, |
479 | .num_ovls = 3, | 657 | .num_ovls = 3, |
480 | .supported_displays = omap3430_dss_supported_displays, | 658 | .supported_displays = omap3430_dss_supported_displays, |
659 | .supported_outputs = omap3430_dss_supported_outputs, | ||
660 | .supported_color_modes = omap3_dss_supported_color_modes, | ||
661 | .overlay_caps = omap3430_dss_overlay_caps, | ||
662 | .clksrc_names = omap3_dss_clk_source_names, | ||
663 | .dss_params = omap3_dss_param_range, | ||
664 | .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB, | ||
665 | .buffer_size_unit = 1, | ||
666 | .burst_size_unit = 8, | ||
667 | }; | ||
668 | |||
669 | /* | ||
670 | * AM35xx DSS Features. This is basically OMAP3 DSS Features without the | ||
671 | * vdds_dsi regulator. | ||
672 | */ | ||
673 | static const struct omap_dss_features am35xx_dss_features = { | ||
674 | .reg_fields = omap3_dss_reg_fields, | ||
675 | .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields), | ||
676 | |||
677 | .features = am35xx_dss_feat_list, | ||
678 | .num_features = ARRAY_SIZE(am35xx_dss_feat_list), | ||
679 | |||
680 | .num_mgrs = 2, | ||
681 | .num_ovls = 3, | ||
682 | .supported_displays = omap3430_dss_supported_displays, | ||
683 | .supported_outputs = omap3430_dss_supported_outputs, | ||
481 | .supported_color_modes = omap3_dss_supported_color_modes, | 684 | .supported_color_modes = omap3_dss_supported_color_modes, |
482 | .overlay_caps = omap3430_dss_overlay_caps, | 685 | .overlay_caps = omap3430_dss_overlay_caps, |
483 | .clksrc_names = omap3_dss_clk_source_names, | 686 | .clksrc_names = omap3_dss_clk_source_names, |
@@ -497,6 +700,7 @@ static const struct omap_dss_features omap3630_dss_features = { | |||
497 | .num_mgrs = 2, | 700 | .num_mgrs = 2, |
498 | .num_ovls = 3, | 701 | .num_ovls = 3, |
499 | .supported_displays = omap3630_dss_supported_displays, | 702 | .supported_displays = omap3630_dss_supported_displays, |
703 | .supported_outputs = omap3630_dss_supported_outputs, | ||
500 | .supported_color_modes = omap3_dss_supported_color_modes, | 704 | .supported_color_modes = omap3_dss_supported_color_modes, |
501 | .overlay_caps = omap3630_dss_overlay_caps, | 705 | .overlay_caps = omap3630_dss_overlay_caps, |
502 | .clksrc_names = omap3_dss_clk_source_names, | 706 | .clksrc_names = omap3_dss_clk_source_names, |
@@ -517,7 +721,9 @@ static const struct omap_dss_features omap4430_es1_0_dss_features = { | |||
517 | 721 | ||
518 | .num_mgrs = 3, | 722 | .num_mgrs = 3, |
519 | .num_ovls = 4, | 723 | .num_ovls = 4, |
724 | .num_wbs = 1, | ||
520 | .supported_displays = omap4_dss_supported_displays, | 725 | .supported_displays = omap4_dss_supported_displays, |
726 | .supported_outputs = omap4_dss_supported_outputs, | ||
521 | .supported_color_modes = omap4_dss_supported_color_modes, | 727 | .supported_color_modes = omap4_dss_supported_color_modes, |
522 | .overlay_caps = omap4_dss_overlay_caps, | 728 | .overlay_caps = omap4_dss_overlay_caps, |
523 | .clksrc_names = omap4_dss_clk_source_names, | 729 | .clksrc_names = omap4_dss_clk_source_names, |
@@ -537,7 +743,9 @@ static const struct omap_dss_features omap4430_es2_0_1_2_dss_features = { | |||
537 | 743 | ||
538 | .num_mgrs = 3, | 744 | .num_mgrs = 3, |
539 | .num_ovls = 4, | 745 | .num_ovls = 4, |
746 | .num_wbs = 1, | ||
540 | .supported_displays = omap4_dss_supported_displays, | 747 | .supported_displays = omap4_dss_supported_displays, |
748 | .supported_outputs = omap4_dss_supported_outputs, | ||
541 | .supported_color_modes = omap4_dss_supported_color_modes, | 749 | .supported_color_modes = omap4_dss_supported_color_modes, |
542 | .overlay_caps = omap4_dss_overlay_caps, | 750 | .overlay_caps = omap4_dss_overlay_caps, |
543 | .clksrc_names = omap4_dss_clk_source_names, | 751 | .clksrc_names = omap4_dss_clk_source_names, |
@@ -557,7 +765,9 @@ static const struct omap_dss_features omap4_dss_features = { | |||
557 | 765 | ||
558 | .num_mgrs = 3, | 766 | .num_mgrs = 3, |
559 | .num_ovls = 4, | 767 | .num_ovls = 4, |
768 | .num_wbs = 1, | ||
560 | .supported_displays = omap4_dss_supported_displays, | 769 | .supported_displays = omap4_dss_supported_displays, |
770 | .supported_outputs = omap4_dss_supported_outputs, | ||
561 | .supported_color_modes = omap4_dss_supported_color_modes, | 771 | .supported_color_modes = omap4_dss_supported_color_modes, |
562 | .overlay_caps = omap4_dss_overlay_caps, | 772 | .overlay_caps = omap4_dss_overlay_caps, |
563 | .clksrc_names = omap4_dss_clk_source_names, | 773 | .clksrc_names = omap4_dss_clk_source_names, |
@@ -567,6 +777,27 @@ static const struct omap_dss_features omap4_dss_features = { | |||
567 | .burst_size_unit = 16, | 777 | .burst_size_unit = 16, |
568 | }; | 778 | }; |
569 | 779 | ||
780 | /* OMAP5 DSS Features */ | ||
781 | static const struct omap_dss_features omap5_dss_features = { | ||
782 | .reg_fields = omap5_dss_reg_fields, | ||
783 | .num_reg_fields = ARRAY_SIZE(omap5_dss_reg_fields), | ||
784 | |||
785 | .features = omap5_dss_feat_list, | ||
786 | .num_features = ARRAY_SIZE(omap5_dss_feat_list), | ||
787 | |||
788 | .num_mgrs = 3, | ||
789 | .num_ovls = 4, | ||
790 | .supported_displays = omap5_dss_supported_displays, | ||
791 | .supported_outputs = omap5_dss_supported_outputs, | ||
792 | .supported_color_modes = omap4_dss_supported_color_modes, | ||
793 | .overlay_caps = omap4_dss_overlay_caps, | ||
794 | .clksrc_names = omap5_dss_clk_source_names, | ||
795 | .dss_params = omap5_dss_param_range, | ||
796 | .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER, | ||
797 | .buffer_size_unit = 16, | ||
798 | .burst_size_unit = 16, | ||
799 | }; | ||
800 | |||
570 | #if defined(CONFIG_OMAP4_DSS_HDMI) | 801 | #if defined(CONFIG_OMAP4_DSS_HDMI) |
571 | /* HDMI OMAP4 Functions*/ | 802 | /* HDMI OMAP4 Functions*/ |
572 | static const struct ti_hdmi_ip_ops omap4_hdmi_functions = { | 803 | static const struct ti_hdmi_ip_ops omap4_hdmi_functions = { |
@@ -612,6 +843,11 @@ int dss_feat_get_num_ovls(void) | |||
612 | return omap_current_dss_features->num_ovls; | 843 | return omap_current_dss_features->num_ovls; |
613 | } | 844 | } |
614 | 845 | ||
846 | int dss_feat_get_num_wbs(void) | ||
847 | { | ||
848 | return omap_current_dss_features->num_wbs; | ||
849 | } | ||
850 | |||
615 | unsigned long dss_feat_get_param_min(enum dss_range_param param) | 851 | unsigned long dss_feat_get_param_min(enum dss_range_param param) |
616 | { | 852 | { |
617 | return omap_current_dss_features->dss_params[param].min; | 853 | return omap_current_dss_features->dss_params[param].min; |
@@ -627,6 +863,11 @@ enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel | |||
627 | return omap_current_dss_features->supported_displays[channel]; | 863 | return omap_current_dss_features->supported_displays[channel]; |
628 | } | 864 | } |
629 | 865 | ||
866 | enum omap_dss_output_id dss_feat_get_supported_outputs(enum omap_channel channel) | ||
867 | { | ||
868 | return omap_current_dss_features->supported_outputs[channel]; | ||
869 | } | ||
870 | |||
630 | enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane) | 871 | enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane) |
631 | { | 872 | { |
632 | return omap_current_dss_features->supported_color_modes[plane]; | 873 | return omap_current_dss_features->supported_color_modes[plane]; |
@@ -694,8 +935,13 @@ void dss_features_init(void) | |||
694 | omap_current_dss_features = &omap2_dss_features; | 935 | omap_current_dss_features = &omap2_dss_features; |
695 | else if (cpu_is_omap3630()) | 936 | else if (cpu_is_omap3630()) |
696 | omap_current_dss_features = &omap3630_dss_features; | 937 | omap_current_dss_features = &omap3630_dss_features; |
697 | else if (cpu_is_omap34xx()) | 938 | else if (cpu_is_omap34xx()) { |
698 | omap_current_dss_features = &omap3430_dss_features; | 939 | if (soc_is_am35xx()) { |
940 | omap_current_dss_features = &am35xx_dss_features; | ||
941 | } else { | ||
942 | omap_current_dss_features = &omap3430_dss_features; | ||
943 | } | ||
944 | } | ||
699 | else if (omap_rev() == OMAP4430_REV_ES1_0) | 945 | else if (omap_rev() == OMAP4430_REV_ES1_0) |
700 | omap_current_dss_features = &omap4430_es1_0_dss_features; | 946 | omap_current_dss_features = &omap4430_es1_0_dss_features; |
701 | else if (omap_rev() == OMAP4430_REV_ES2_0 || | 947 | else if (omap_rev() == OMAP4430_REV_ES2_0 || |
@@ -704,6 +950,8 @@ void dss_features_init(void) | |||
704 | omap_current_dss_features = &omap4430_es2_0_1_2_dss_features; | 950 | omap_current_dss_features = &omap4430_es2_0_1_2_dss_features; |
705 | else if (cpu_is_omap44xx()) | 951 | else if (cpu_is_omap44xx()) |
706 | omap_current_dss_features = &omap4_dss_features; | 952 | omap_current_dss_features = &omap4_dss_features; |
953 | else if (soc_is_omap54xx()) | ||
954 | omap_current_dss_features = &omap5_dss_features; | ||
707 | else | 955 | else |
708 | DSSWARN("Unsupported OMAP version"); | 956 | DSSWARN("Unsupported OMAP version"); |
709 | } | 957 | } |
diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h index 996ffcbfed58..9218113b5e88 100644 --- a/drivers/video/omap2/dss/dss_features.h +++ b/drivers/video/omap2/dss/dss_features.h | |||
@@ -50,6 +50,7 @@ enum dss_feat_id { | |||
50 | FEAT_DSI_VC_OCP_WIDTH, | 50 | FEAT_DSI_VC_OCP_WIDTH, |
51 | FEAT_DSI_REVERSE_TXCLKESC, | 51 | FEAT_DSI_REVERSE_TXCLKESC, |
52 | FEAT_DSI_GNQ, | 52 | FEAT_DSI_GNQ, |
53 | FEAT_DPI_USES_VDDS_DSI, | ||
53 | FEAT_HDMI_CTS_SWMODE, | 54 | FEAT_HDMI_CTS_SWMODE, |
54 | FEAT_HDMI_AUDIO_USE_MCLK, | 55 | FEAT_HDMI_AUDIO_USE_MCLK, |
55 | FEAT_HANDLE_UV_SEPARATE, | 56 | FEAT_HANDLE_UV_SEPARATE, |
@@ -64,6 +65,9 @@ enum dss_feat_id { | |||
64 | /* An unknown HW bug causing the normal FIFO thresholds not to work */ | 65 | /* An unknown HW bug causing the normal FIFO thresholds not to work */ |
65 | FEAT_OMAP3_DSI_FIFO_BUG, | 66 | FEAT_OMAP3_DSI_FIFO_BUG, |
66 | FEAT_BURST_2D, | 67 | FEAT_BURST_2D, |
68 | FEAT_DSI_PLL_SELFREQDCO, | ||
69 | FEAT_DSI_PLL_REFSEL, | ||
70 | FEAT_DSI_PHY_DCC, | ||
67 | }; | 71 | }; |
68 | 72 | ||
69 | /* DSS register field id */ | 73 | /* DSS register field id */ |
@@ -91,6 +95,7 @@ enum dss_range_param { | |||
91 | FEAT_PARAM_DSIPLL_REGM_DSI, | 95 | FEAT_PARAM_DSIPLL_REGM_DSI, |
92 | FEAT_PARAM_DSIPLL_FINT, | 96 | FEAT_PARAM_DSIPLL_FINT, |
93 | FEAT_PARAM_DSIPLL_LPDIV, | 97 | FEAT_PARAM_DSIPLL_LPDIV, |
98 | FEAT_PARAM_DSI_FCK, | ||
94 | FEAT_PARAM_DOWNSCALE, | 99 | FEAT_PARAM_DOWNSCALE, |
95 | FEAT_PARAM_LINEWIDTH, | 100 | FEAT_PARAM_LINEWIDTH, |
96 | FEAT_PARAM_MGR_WIDTH, | 101 | FEAT_PARAM_MGR_WIDTH, |
@@ -100,9 +105,11 @@ enum dss_range_param { | |||
100 | /* DSS Feature Functions */ | 105 | /* DSS Feature Functions */ |
101 | int dss_feat_get_num_mgrs(void); | 106 | int dss_feat_get_num_mgrs(void); |
102 | int dss_feat_get_num_ovls(void); | 107 | int dss_feat_get_num_ovls(void); |
108 | int dss_feat_get_num_wbs(void); | ||
103 | unsigned long dss_feat_get_param_min(enum dss_range_param param); | 109 | unsigned long dss_feat_get_param_min(enum dss_range_param param); |
104 | unsigned long dss_feat_get_param_max(enum dss_range_param param); | 110 | unsigned long dss_feat_get_param_max(enum dss_range_param param); |
105 | enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel); | 111 | enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel); |
112 | enum omap_dss_output_id dss_feat_get_supported_outputs(enum omap_channel channel); | ||
106 | enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane); | 113 | enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane); |
107 | enum omap_overlay_caps dss_feat_get_overlay_caps(enum omap_plane plane); | 114 | enum omap_overlay_caps dss_feat_get_overlay_caps(enum omap_plane plane); |
108 | bool dss_feat_color_mode_supported(enum omap_plane plane, | 115 | bool dss_feat_color_mode_supported(enum omap_plane plane, |
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index 060216fdc578..a48a7dd75b33 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c | |||
@@ -32,6 +32,8 @@ | |||
32 | #include <linux/platform_device.h> | 32 | #include <linux/platform_device.h> |
33 | #include <linux/pm_runtime.h> | 33 | #include <linux/pm_runtime.h> |
34 | #include <linux/clk.h> | 34 | #include <linux/clk.h> |
35 | #include <linux/gpio.h> | ||
36 | #include <linux/regulator/consumer.h> | ||
35 | #include <video/omapdss.h> | 37 | #include <video/omapdss.h> |
36 | 38 | ||
37 | #include "ti_hdmi.h" | 39 | #include "ti_hdmi.h" |
@@ -61,6 +63,13 @@ static struct { | |||
61 | struct hdmi_ip_data ip_data; | 63 | struct hdmi_ip_data ip_data; |
62 | 64 | ||
63 | struct clk *sys_clk; | 65 | struct clk *sys_clk; |
66 | struct regulator *vdda_hdmi_dac_reg; | ||
67 | |||
68 | int ct_cp_hpd_gpio; | ||
69 | int ls_oe_gpio; | ||
70 | int hpd_gpio; | ||
71 | |||
72 | struct omap_dss_output output; | ||
64 | } hdmi; | 73 | } hdmi; |
65 | 74 | ||
66 | /* | 75 | /* |
@@ -314,12 +323,47 @@ static void hdmi_runtime_put(void) | |||
314 | 323 | ||
315 | static int __init hdmi_init_display(struct omap_dss_device *dssdev) | 324 | static int __init hdmi_init_display(struct omap_dss_device *dssdev) |
316 | { | 325 | { |
326 | int r; | ||
327 | |||
328 | struct gpio gpios[] = { | ||
329 | { hdmi.ct_cp_hpd_gpio, GPIOF_OUT_INIT_LOW, "hdmi_ct_cp_hpd" }, | ||
330 | { hdmi.ls_oe_gpio, GPIOF_OUT_INIT_LOW, "hdmi_ls_oe" }, | ||
331 | { hdmi.hpd_gpio, GPIOF_DIR_IN, "hdmi_hpd" }, | ||
332 | }; | ||
333 | |||
317 | DSSDBG("init_display\n"); | 334 | DSSDBG("init_display\n"); |
318 | 335 | ||
319 | dss_init_hdmi_ip_ops(&hdmi.ip_data); | 336 | dss_init_hdmi_ip_ops(&hdmi.ip_data); |
337 | |||
338 | if (hdmi.vdda_hdmi_dac_reg == NULL) { | ||
339 | struct regulator *reg; | ||
340 | |||
341 | reg = devm_regulator_get(&hdmi.pdev->dev, "vdda_hdmi_dac"); | ||
342 | |||
343 | if (IS_ERR(reg)) { | ||
344 | DSSERR("can't get VDDA_HDMI_DAC regulator\n"); | ||
345 | return PTR_ERR(reg); | ||
346 | } | ||
347 | |||
348 | hdmi.vdda_hdmi_dac_reg = reg; | ||
349 | } | ||
350 | |||
351 | r = gpio_request_array(gpios, ARRAY_SIZE(gpios)); | ||
352 | if (r) | ||
353 | return r; | ||
354 | |||
320 | return 0; | 355 | return 0; |
321 | } | 356 | } |
322 | 357 | ||
358 | static void __exit hdmi_uninit_display(struct omap_dss_device *dssdev) | ||
359 | { | ||
360 | DSSDBG("uninit_display\n"); | ||
361 | |||
362 | gpio_free(hdmi.ct_cp_hpd_gpio); | ||
363 | gpio_free(hdmi.ls_oe_gpio); | ||
364 | gpio_free(hdmi.hpd_gpio); | ||
365 | } | ||
366 | |||
323 | static const struct hdmi_config *hdmi_find_timing( | 367 | static const struct hdmi_config *hdmi_find_timing( |
324 | const struct hdmi_config *timings_arr, | 368 | const struct hdmi_config *timings_arr, |
325 | int len) | 369 | int len) |
@@ -459,32 +503,30 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, | |||
459 | static int hdmi_power_on(struct omap_dss_device *dssdev) | 503 | static int hdmi_power_on(struct omap_dss_device *dssdev) |
460 | { | 504 | { |
461 | int r; | 505 | int r; |
462 | const struct hdmi_config *timing; | ||
463 | struct omap_video_timings *p; | 506 | struct omap_video_timings *p; |
507 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
464 | unsigned long phy; | 508 | unsigned long phy; |
465 | 509 | ||
510 | gpio_set_value(hdmi.ct_cp_hpd_gpio, 1); | ||
511 | gpio_set_value(hdmi.ls_oe_gpio, 1); | ||
512 | |||
513 | /* wait 300us after CT_CP_HPD for the 5V power output to reach 90% */ | ||
514 | udelay(300); | ||
515 | |||
516 | r = regulator_enable(hdmi.vdda_hdmi_dac_reg); | ||
517 | if (r) | ||
518 | goto err_vdac_enable; | ||
519 | |||
466 | r = hdmi_runtime_get(); | 520 | r = hdmi_runtime_get(); |
467 | if (r) | 521 | if (r) |
468 | return r; | 522 | goto err_runtime_get; |
469 | 523 | ||
470 | dss_mgr_disable(dssdev->manager); | 524 | dss_mgr_disable(mgr); |
471 | 525 | ||
472 | p = &dssdev->panel.timings; | 526 | p = &hdmi.ip_data.cfg.timings; |
473 | 527 | ||
474 | DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", | 528 | DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res); |
475 | dssdev->panel.timings.x_res, | ||
476 | dssdev->panel.timings.y_res); | ||
477 | 529 | ||
478 | timing = hdmi_get_timings(); | ||
479 | if (timing == NULL) { | ||
480 | /* HDMI code 4 corresponds to 640 * 480 VGA */ | ||
481 | hdmi.ip_data.cfg.cm.code = 4; | ||
482 | /* DVI mode 1 corresponds to HDMI 0 to DVI */ | ||
483 | hdmi.ip_data.cfg.cm.mode = HDMI_DVI; | ||
484 | hdmi.ip_data.cfg = vesa_timings[0]; | ||
485 | } else { | ||
486 | hdmi.ip_data.cfg = *timing; | ||
487 | } | ||
488 | phy = p->pixel_clock; | 530 | phy = p->pixel_clock; |
489 | 531 | ||
490 | hdmi_compute_pll(dssdev, phy, &hdmi.ip_data.pll_data); | 532 | hdmi_compute_pll(dssdev, phy, &hdmi.ip_data.pll_data); |
@@ -495,13 +537,13 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) | |||
495 | r = hdmi.ip_data.ops->pll_enable(&hdmi.ip_data); | 537 | r = hdmi.ip_data.ops->pll_enable(&hdmi.ip_data); |
496 | if (r) { | 538 | if (r) { |
497 | DSSDBG("Failed to lock PLL\n"); | 539 | DSSDBG("Failed to lock PLL\n"); |
498 | goto err; | 540 | goto err_pll_enable; |
499 | } | 541 | } |
500 | 542 | ||
501 | r = hdmi.ip_data.ops->phy_enable(&hdmi.ip_data); | 543 | r = hdmi.ip_data.ops->phy_enable(&hdmi.ip_data); |
502 | if (r) { | 544 | if (r) { |
503 | DSSDBG("Failed to start PHY\n"); | 545 | DSSDBG("Failed to start PHY\n"); |
504 | goto err; | 546 | goto err_phy_enable; |
505 | } | 547 | } |
506 | 548 | ||
507 | hdmi.ip_data.ops->video_configure(&hdmi.ip_data); | 549 | hdmi.ip_data.ops->video_configure(&hdmi.ip_data); |
@@ -521,13 +563,13 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) | |||
521 | dispc_enable_gamma_table(0); | 563 | dispc_enable_gamma_table(0); |
522 | 564 | ||
523 | /* tv size */ | 565 | /* tv size */ |
524 | dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings); | 566 | dss_mgr_set_timings(mgr, p); |
525 | 567 | ||
526 | r = hdmi.ip_data.ops->video_enable(&hdmi.ip_data); | 568 | r = hdmi.ip_data.ops->video_enable(&hdmi.ip_data); |
527 | if (r) | 569 | if (r) |
528 | goto err_vid_enable; | 570 | goto err_vid_enable; |
529 | 571 | ||
530 | r = dss_mgr_enable(dssdev->manager); | 572 | r = dss_mgr_enable(mgr); |
531 | if (r) | 573 | if (r) |
532 | goto err_mgr_enable; | 574 | goto err_mgr_enable; |
533 | 575 | ||
@@ -537,20 +579,33 @@ err_mgr_enable: | |||
537 | hdmi.ip_data.ops->video_disable(&hdmi.ip_data); | 579 | hdmi.ip_data.ops->video_disable(&hdmi.ip_data); |
538 | err_vid_enable: | 580 | err_vid_enable: |
539 | hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); | 581 | hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); |
582 | err_phy_enable: | ||
540 | hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); | 583 | hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); |
541 | err: | 584 | err_pll_enable: |
542 | hdmi_runtime_put(); | 585 | hdmi_runtime_put(); |
586 | err_runtime_get: | ||
587 | regulator_disable(hdmi.vdda_hdmi_dac_reg); | ||
588 | err_vdac_enable: | ||
589 | gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); | ||
590 | gpio_set_value(hdmi.ls_oe_gpio, 0); | ||
543 | return -EIO; | 591 | return -EIO; |
544 | } | 592 | } |
545 | 593 | ||
546 | static void hdmi_power_off(struct omap_dss_device *dssdev) | 594 | static void hdmi_power_off(struct omap_dss_device *dssdev) |
547 | { | 595 | { |
548 | dss_mgr_disable(dssdev->manager); | 596 | struct omap_overlay_manager *mgr = dssdev->output->manager; |
597 | |||
598 | dss_mgr_disable(mgr); | ||
549 | 599 | ||
550 | hdmi.ip_data.ops->video_disable(&hdmi.ip_data); | 600 | hdmi.ip_data.ops->video_disable(&hdmi.ip_data); |
551 | hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); | 601 | hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); |
552 | hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); | 602 | hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); |
553 | hdmi_runtime_put(); | 603 | hdmi_runtime_put(); |
604 | |||
605 | regulator_disable(hdmi.vdda_hdmi_dac_reg); | ||
606 | |||
607 | gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); | ||
608 | gpio_set_value(hdmi.ls_oe_gpio, 0); | ||
554 | } | 609 | } |
555 | 610 | ||
556 | int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, | 611 | int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, |
@@ -567,25 +622,22 @@ int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, | |||
567 | 622 | ||
568 | } | 623 | } |
569 | 624 | ||
570 | void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev) | 625 | void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev, |
626 | struct omap_video_timings *timings) | ||
571 | { | 627 | { |
572 | struct hdmi_cm cm; | 628 | struct hdmi_cm cm; |
629 | const struct hdmi_config *t; | ||
573 | 630 | ||
574 | cm = hdmi_get_code(&dssdev->panel.timings); | 631 | mutex_lock(&hdmi.lock); |
575 | hdmi.ip_data.cfg.cm.code = cm.code; | ||
576 | hdmi.ip_data.cfg.cm.mode = cm.mode; | ||
577 | 632 | ||
578 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { | 633 | cm = hdmi_get_code(timings); |
579 | int r; | 634 | hdmi.ip_data.cfg.cm = cm; |
580 | 635 | ||
581 | hdmi_power_off(dssdev); | 636 | t = hdmi_get_timings(); |
637 | if (t != NULL) | ||
638 | hdmi.ip_data.cfg = *t; | ||
582 | 639 | ||
583 | r = hdmi_power_on(dssdev); | 640 | mutex_unlock(&hdmi.lock); |
584 | if (r) | ||
585 | DSSERR("failed to power on device\n"); | ||
586 | } else { | ||
587 | dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings); | ||
588 | } | ||
589 | } | 641 | } |
590 | 642 | ||
591 | static void hdmi_dump_regs(struct seq_file *s) | 643 | static void hdmi_dump_regs(struct seq_file *s) |
@@ -640,20 +692,20 @@ bool omapdss_hdmi_detect(void) | |||
640 | 692 | ||
641 | int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev) | 693 | int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev) |
642 | { | 694 | { |
643 | struct omap_dss_hdmi_data *priv = dssdev->data; | 695 | struct omap_dss_output *out = dssdev->output; |
644 | int r = 0; | 696 | int r = 0; |
645 | 697 | ||
646 | DSSDBG("ENTER hdmi_display_enable\n"); | 698 | DSSDBG("ENTER hdmi_display_enable\n"); |
647 | 699 | ||
648 | mutex_lock(&hdmi.lock); | 700 | mutex_lock(&hdmi.lock); |
649 | 701 | ||
650 | if (dssdev->manager == NULL) { | 702 | if (out == NULL || out->manager == NULL) { |
651 | DSSERR("failed to enable display: no manager\n"); | 703 | DSSERR("failed to enable display: no output/manager\n"); |
652 | r = -ENODEV; | 704 | r = -ENODEV; |
653 | goto err0; | 705 | goto err0; |
654 | } | 706 | } |
655 | 707 | ||
656 | hdmi.ip_data.hpd_gpio = priv->hpd_gpio; | 708 | hdmi.ip_data.hpd_gpio = hdmi.hpd_gpio; |
657 | 709 | ||
658 | r = omap_dss_start_device(dssdev); | 710 | r = omap_dss_start_device(dssdev); |
659 | if (r) { | 711 | if (r) { |
@@ -661,26 +713,15 @@ int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev) | |||
661 | goto err0; | 713 | goto err0; |
662 | } | 714 | } |
663 | 715 | ||
664 | if (dssdev->platform_enable) { | ||
665 | r = dssdev->platform_enable(dssdev); | ||
666 | if (r) { | ||
667 | DSSERR("failed to enable GPIO's\n"); | ||
668 | goto err1; | ||
669 | } | ||
670 | } | ||
671 | |||
672 | r = hdmi_power_on(dssdev); | 716 | r = hdmi_power_on(dssdev); |
673 | if (r) { | 717 | if (r) { |
674 | DSSERR("failed to power on device\n"); | 718 | DSSERR("failed to power on device\n"); |
675 | goto err2; | 719 | goto err1; |
676 | } | 720 | } |
677 | 721 | ||
678 | mutex_unlock(&hdmi.lock); | 722 | mutex_unlock(&hdmi.lock); |
679 | return 0; | 723 | return 0; |
680 | 724 | ||
681 | err2: | ||
682 | if (dssdev->platform_disable) | ||
683 | dssdev->platform_disable(dssdev); | ||
684 | err1: | 725 | err1: |
685 | omap_dss_stop_device(dssdev); | 726 | omap_dss_stop_device(dssdev); |
686 | err0: | 727 | err0: |
@@ -696,9 +737,6 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev) | |||
696 | 737 | ||
697 | hdmi_power_off(dssdev); | 738 | hdmi_power_off(dssdev); |
698 | 739 | ||
699 | if (dssdev->platform_disable) | ||
700 | dssdev->platform_disable(dssdev); | ||
701 | |||
702 | omap_dss_stop_device(dssdev); | 740 | omap_dss_stop_device(dssdev); |
703 | 741 | ||
704 | mutex_unlock(&hdmi.lock); | 742 | mutex_unlock(&hdmi.lock); |
@@ -869,10 +907,14 @@ int hdmi_audio_config(struct omap_dss_audio *audio) | |||
869 | 907 | ||
870 | #endif | 908 | #endif |
871 | 909 | ||
872 | static void __init hdmi_probe_pdata(struct platform_device *pdev) | 910 | static struct omap_dss_device * __init hdmi_find_dssdev(struct platform_device *pdev) |
873 | { | 911 | { |
874 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | 912 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; |
875 | int r, i; | 913 | const char *def_disp_name = dss_get_default_display_name(); |
914 | struct omap_dss_device *def_dssdev; | ||
915 | int i; | ||
916 | |||
917 | def_dssdev = NULL; | ||
876 | 918 | ||
877 | for (i = 0; i < pdata->num_devices; ++i) { | 919 | for (i = 0; i < pdata->num_devices; ++i) { |
878 | struct omap_dss_device *dssdev = pdata->devices[i]; | 920 | struct omap_dss_device *dssdev = pdata->devices[i]; |
@@ -880,17 +922,76 @@ static void __init hdmi_probe_pdata(struct platform_device *pdev) | |||
880 | if (dssdev->type != OMAP_DISPLAY_TYPE_HDMI) | 922 | if (dssdev->type != OMAP_DISPLAY_TYPE_HDMI) |
881 | continue; | 923 | continue; |
882 | 924 | ||
883 | r = hdmi_init_display(dssdev); | 925 | if (def_dssdev == NULL) |
884 | if (r) { | 926 | def_dssdev = dssdev; |
885 | DSSERR("device %s init failed: %d\n", dssdev->name, r); | 927 | |
886 | continue; | 928 | if (def_disp_name != NULL && |
929 | strcmp(dssdev->name, def_disp_name) == 0) { | ||
930 | def_dssdev = dssdev; | ||
931 | break; | ||
887 | } | 932 | } |
933 | } | ||
888 | 934 | ||
889 | r = omap_dss_register_device(dssdev, &pdev->dev, i); | 935 | return def_dssdev; |
890 | if (r) | 936 | } |
891 | DSSERR("device %s register failed: %d\n", | 937 | |
892 | dssdev->name, r); | 938 | static void __init hdmi_probe_pdata(struct platform_device *pdev) |
939 | { | ||
940 | struct omap_dss_device *plat_dssdev; | ||
941 | struct omap_dss_device *dssdev; | ||
942 | struct omap_dss_hdmi_data *priv; | ||
943 | int r; | ||
944 | |||
945 | plat_dssdev = hdmi_find_dssdev(pdev); | ||
946 | |||
947 | if (!plat_dssdev) | ||
948 | return; | ||
949 | |||
950 | dssdev = dss_alloc_and_init_device(&pdev->dev); | ||
951 | if (!dssdev) | ||
952 | return; | ||
953 | |||
954 | dss_copy_device_pdata(dssdev, plat_dssdev); | ||
955 | |||
956 | priv = dssdev->data; | ||
957 | |||
958 | hdmi.ct_cp_hpd_gpio = priv->ct_cp_hpd_gpio; | ||
959 | hdmi.ls_oe_gpio = priv->ls_oe_gpio; | ||
960 | hdmi.hpd_gpio = priv->hpd_gpio; | ||
961 | |||
962 | dssdev->channel = OMAP_DSS_CHANNEL_DIGIT; | ||
963 | |||
964 | r = hdmi_init_display(dssdev); | ||
965 | if (r) { | ||
966 | DSSERR("device %s init failed: %d\n", dssdev->name, r); | ||
967 | dss_put_device(dssdev); | ||
968 | return; | ||
893 | } | 969 | } |
970 | |||
971 | r = dss_add_device(dssdev); | ||
972 | if (r) { | ||
973 | DSSERR("device %s register failed: %d\n", dssdev->name, r); | ||
974 | dss_put_device(dssdev); | ||
975 | return; | ||
976 | } | ||
977 | } | ||
978 | |||
979 | static void __init hdmi_init_output(struct platform_device *pdev) | ||
980 | { | ||
981 | struct omap_dss_output *out = &hdmi.output; | ||
982 | |||
983 | out->pdev = pdev; | ||
984 | out->id = OMAP_DSS_OUTPUT_HDMI; | ||
985 | out->type = OMAP_DISPLAY_TYPE_HDMI; | ||
986 | |||
987 | dss_register_output(out); | ||
988 | } | ||
989 | |||
990 | static void __exit hdmi_uninit_output(struct platform_device *pdev) | ||
991 | { | ||
992 | struct omap_dss_output *out = &hdmi.output; | ||
993 | |||
994 | dss_unregister_output(out); | ||
894 | } | 995 | } |
895 | 996 | ||
896 | /* HDMI HW IP initialisation */ | 997 | /* HDMI HW IP initialisation */ |
@@ -929,23 +1030,37 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev) | |||
929 | hdmi.ip_data.core_av_offset = HDMI_CORE_AV; | 1030 | hdmi.ip_data.core_av_offset = HDMI_CORE_AV; |
930 | hdmi.ip_data.pll_offset = HDMI_PLLCTRL; | 1031 | hdmi.ip_data.pll_offset = HDMI_PLLCTRL; |
931 | hdmi.ip_data.phy_offset = HDMI_PHY; | 1032 | hdmi.ip_data.phy_offset = HDMI_PHY; |
1033 | |||
932 | mutex_init(&hdmi.ip_data.lock); | 1034 | mutex_init(&hdmi.ip_data.lock); |
933 | 1035 | ||
934 | hdmi_panel_init(); | 1036 | hdmi_panel_init(); |
935 | 1037 | ||
936 | dss_debugfs_create_file("hdmi", hdmi_dump_regs); | 1038 | dss_debugfs_create_file("hdmi", hdmi_dump_regs); |
937 | 1039 | ||
1040 | hdmi_init_output(pdev); | ||
1041 | |||
938 | hdmi_probe_pdata(pdev); | 1042 | hdmi_probe_pdata(pdev); |
939 | 1043 | ||
940 | return 0; | 1044 | return 0; |
941 | } | 1045 | } |
942 | 1046 | ||
1047 | static int __exit hdmi_remove_child(struct device *dev, void *data) | ||
1048 | { | ||
1049 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
1050 | hdmi_uninit_display(dssdev); | ||
1051 | return 0; | ||
1052 | } | ||
1053 | |||
943 | static int __exit omapdss_hdmihw_remove(struct platform_device *pdev) | 1054 | static int __exit omapdss_hdmihw_remove(struct platform_device *pdev) |
944 | { | 1055 | { |
945 | omap_dss_unregister_child_devices(&pdev->dev); | 1056 | device_for_each_child(&pdev->dev, NULL, hdmi_remove_child); |
1057 | |||
1058 | dss_unregister_child_devices(&pdev->dev); | ||
946 | 1059 | ||
947 | hdmi_panel_exit(); | 1060 | hdmi_panel_exit(); |
948 | 1061 | ||
1062 | hdmi_uninit_output(pdev); | ||
1063 | |||
949 | pm_runtime_disable(&pdev->dev); | 1064 | pm_runtime_disable(&pdev->dev); |
950 | 1065 | ||
951 | hdmi_put_clocks(); | 1066 | hdmi_put_clocks(); |
diff --git a/drivers/video/omap2/dss/hdmi_panel.c b/drivers/video/omap2/dss/hdmi_panel.c index e10844faadf9..69fb115bab32 100644 --- a/drivers/video/omap2/dss/hdmi_panel.c +++ b/drivers/video/omap2/dss/hdmi_panel.c | |||
@@ -41,17 +41,34 @@ static struct { | |||
41 | 41 | ||
42 | static int hdmi_panel_probe(struct omap_dss_device *dssdev) | 42 | static int hdmi_panel_probe(struct omap_dss_device *dssdev) |
43 | { | 43 | { |
44 | /* Initialize default timings to VGA in DVI mode */ | ||
45 | const struct omap_video_timings default_timings = { | ||
46 | .x_res = 640, | ||
47 | .y_res = 480, | ||
48 | .pixel_clock = 25175, | ||
49 | .hsw = 96, | ||
50 | .hfp = 16, | ||
51 | .hbp = 48, | ||
52 | .vsw = 2, | ||
53 | .vfp = 11, | ||
54 | .vbp = 31, | ||
55 | |||
56 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
57 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
58 | |||
59 | .interlace = false, | ||
60 | }; | ||
61 | |||
44 | DSSDBG("ENTER hdmi_panel_probe\n"); | 62 | DSSDBG("ENTER hdmi_panel_probe\n"); |
45 | 63 | ||
46 | dssdev->panel.timings = (struct omap_video_timings) | 64 | dssdev->panel.timings = default_timings; |
47 | { 640, 480, 25175, 96, 16, 48, 2, 11, 31, | ||
48 | OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, | ||
49 | false, | ||
50 | }; | ||
51 | 65 | ||
52 | DSSDBG("hdmi_panel_probe x_res= %d y_res = %d\n", | 66 | DSSDBG("hdmi_panel_probe x_res= %d y_res = %d\n", |
53 | dssdev->panel.timings.x_res, | 67 | dssdev->panel.timings.x_res, |
54 | dssdev->panel.timings.y_res); | 68 | dssdev->panel.timings.y_res); |
69 | |||
70 | omapdss_hdmi_display_set_timing(dssdev, &dssdev->panel.timings); | ||
71 | |||
55 | return 0; | 72 | return 0; |
56 | } | 73 | } |
57 | 74 | ||
@@ -228,6 +245,8 @@ static int hdmi_panel_enable(struct omap_dss_device *dssdev) | |||
228 | goto err; | 245 | goto err; |
229 | } | 246 | } |
230 | 247 | ||
248 | omapdss_hdmi_display_set_timing(dssdev, &dssdev->panel.timings); | ||
249 | |||
231 | r = omapdss_hdmi_display_enable(dssdev); | 250 | r = omapdss_hdmi_display_enable(dssdev); |
232 | if (r) { | 251 | if (r) { |
233 | DSSERR("failed to power on\n"); | 252 | DSSERR("failed to power on\n"); |
@@ -336,8 +355,8 @@ static void hdmi_set_timings(struct omap_dss_device *dssdev, | |||
336 | */ | 355 | */ |
337 | hdmi_panel_audio_disable(dssdev); | 356 | hdmi_panel_audio_disable(dssdev); |
338 | 357 | ||
358 | omapdss_hdmi_display_set_timing(dssdev, timings); | ||
339 | dssdev->panel.timings = *timings; | 359 | dssdev->panel.timings = *timings; |
340 | omapdss_hdmi_display_set_timing(dssdev); | ||
341 | 360 | ||
342 | mutex_unlock(&hdmi.lock); | 361 | mutex_unlock(&hdmi.lock); |
343 | } | 362 | } |
diff --git a/drivers/video/omap2/dss/manager-sysfs.c b/drivers/video/omap2/dss/manager-sysfs.c new file mode 100644 index 000000000000..9a2fb59b6f89 --- /dev/null +++ b/drivers/video/omap2/dss/manager-sysfs.c | |||
@@ -0,0 +1,512 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Nokia Corporation | ||
3 | * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> | ||
4 | * | ||
5 | * Some code and ideas taken from drivers/video/omap/ driver | ||
6 | * by Imre Deak. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License version 2 as published by | ||
10 | * the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along with | ||
18 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
19 | */ | ||
20 | |||
21 | #define DSS_SUBSYS_NAME "MANAGER" | ||
22 | |||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | #include <linux/jiffies.h> | ||
28 | |||
29 | #include <video/omapdss.h> | ||
30 | |||
31 | #include "dss.h" | ||
32 | #include "dss_features.h" | ||
33 | |||
34 | static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf) | ||
35 | { | ||
36 | return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name); | ||
37 | } | ||
38 | |||
39 | static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf) | ||
40 | { | ||
41 | struct omap_dss_device *dssdev = mgr->get_device(mgr); | ||
42 | |||
43 | return snprintf(buf, PAGE_SIZE, "%s\n", dssdev ? | ||
44 | dssdev->name : "<none>"); | ||
45 | } | ||
46 | |||
47 | static ssize_t manager_display_store(struct omap_overlay_manager *mgr, | ||
48 | const char *buf, size_t size) | ||
49 | { | ||
50 | int r = 0; | ||
51 | size_t len = size; | ||
52 | struct omap_dss_device *dssdev = NULL; | ||
53 | |||
54 | int match(struct omap_dss_device *dssdev, void *data) | ||
55 | { | ||
56 | const char *str = data; | ||
57 | return sysfs_streq(dssdev->name, str); | ||
58 | } | ||
59 | |||
60 | if (buf[size-1] == '\n') | ||
61 | --len; | ||
62 | |||
63 | if (len > 0) | ||
64 | dssdev = omap_dss_find_device((void *)buf, match); | ||
65 | |||
66 | if (len > 0 && dssdev == NULL) | ||
67 | return -EINVAL; | ||
68 | |||
69 | if (dssdev) | ||
70 | DSSDBG("display %s found\n", dssdev->name); | ||
71 | |||
72 | if (mgr->output) { | ||
73 | r = mgr->unset_output(mgr); | ||
74 | if (r) { | ||
75 | DSSERR("failed to unset current output\n"); | ||
76 | goto put_device; | ||
77 | } | ||
78 | } | ||
79 | |||
80 | if (dssdev) { | ||
81 | struct omap_dss_output *out = dssdev->output; | ||
82 | |||
83 | /* | ||
84 | * a registered device should have an output connected to it | ||
85 | * already | ||
86 | */ | ||
87 | if (!out) { | ||
88 | DSSERR("device has no output connected to it\n"); | ||
89 | goto put_device; | ||
90 | } | ||
91 | |||
92 | r = mgr->set_output(mgr, out); | ||
93 | if (r) { | ||
94 | DSSERR("failed to set manager output\n"); | ||
95 | goto put_device; | ||
96 | } | ||
97 | |||
98 | r = mgr->apply(mgr); | ||
99 | if (r) { | ||
100 | DSSERR("failed to apply dispc config\n"); | ||
101 | goto put_device; | ||
102 | } | ||
103 | } | ||
104 | |||
105 | put_device: | ||
106 | if (dssdev) | ||
107 | omap_dss_put_device(dssdev); | ||
108 | |||
109 | return r ? r : size; | ||
110 | } | ||
111 | |||
112 | static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr, | ||
113 | char *buf) | ||
114 | { | ||
115 | struct omap_overlay_manager_info info; | ||
116 | |||
117 | mgr->get_manager_info(mgr, &info); | ||
118 | |||
119 | return snprintf(buf, PAGE_SIZE, "%#x\n", info.default_color); | ||
120 | } | ||
121 | |||
122 | static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr, | ||
123 | const char *buf, size_t size) | ||
124 | { | ||
125 | struct omap_overlay_manager_info info; | ||
126 | u32 color; | ||
127 | int r; | ||
128 | |||
129 | r = kstrtouint(buf, 0, &color); | ||
130 | if (r) | ||
131 | return r; | ||
132 | |||
133 | mgr->get_manager_info(mgr, &info); | ||
134 | |||
135 | info.default_color = color; | ||
136 | |||
137 | r = mgr->set_manager_info(mgr, &info); | ||
138 | if (r) | ||
139 | return r; | ||
140 | |||
141 | r = mgr->apply(mgr); | ||
142 | if (r) | ||
143 | return r; | ||
144 | |||
145 | return size; | ||
146 | } | ||
147 | |||
148 | static const char *trans_key_type_str[] = { | ||
149 | "gfx-destination", | ||
150 | "video-source", | ||
151 | }; | ||
152 | |||
153 | static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr, | ||
154 | char *buf) | ||
155 | { | ||
156 | enum omap_dss_trans_key_type key_type; | ||
157 | struct omap_overlay_manager_info info; | ||
158 | |||
159 | mgr->get_manager_info(mgr, &info); | ||
160 | |||
161 | key_type = info.trans_key_type; | ||
162 | BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str)); | ||
163 | |||
164 | return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]); | ||
165 | } | ||
166 | |||
167 | static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr, | ||
168 | const char *buf, size_t size) | ||
169 | { | ||
170 | enum omap_dss_trans_key_type key_type; | ||
171 | struct omap_overlay_manager_info info; | ||
172 | int r; | ||
173 | |||
174 | for (key_type = OMAP_DSS_COLOR_KEY_GFX_DST; | ||
175 | key_type < ARRAY_SIZE(trans_key_type_str); key_type++) { | ||
176 | if (sysfs_streq(buf, trans_key_type_str[key_type])) | ||
177 | break; | ||
178 | } | ||
179 | |||
180 | if (key_type == ARRAY_SIZE(trans_key_type_str)) | ||
181 | return -EINVAL; | ||
182 | |||
183 | mgr->get_manager_info(mgr, &info); | ||
184 | |||
185 | info.trans_key_type = key_type; | ||
186 | |||
187 | r = mgr->set_manager_info(mgr, &info); | ||
188 | if (r) | ||
189 | return r; | ||
190 | |||
191 | r = mgr->apply(mgr); | ||
192 | if (r) | ||
193 | return r; | ||
194 | |||
195 | return size; | ||
196 | } | ||
197 | |||
198 | static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr, | ||
199 | char *buf) | ||
200 | { | ||
201 | struct omap_overlay_manager_info info; | ||
202 | |||
203 | mgr->get_manager_info(mgr, &info); | ||
204 | |||
205 | return snprintf(buf, PAGE_SIZE, "%#x\n", info.trans_key); | ||
206 | } | ||
207 | |||
208 | static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr, | ||
209 | const char *buf, size_t size) | ||
210 | { | ||
211 | struct omap_overlay_manager_info info; | ||
212 | u32 key_value; | ||
213 | int r; | ||
214 | |||
215 | r = kstrtouint(buf, 0, &key_value); | ||
216 | if (r) | ||
217 | return r; | ||
218 | |||
219 | mgr->get_manager_info(mgr, &info); | ||
220 | |||
221 | info.trans_key = key_value; | ||
222 | |||
223 | r = mgr->set_manager_info(mgr, &info); | ||
224 | if (r) | ||
225 | return r; | ||
226 | |||
227 | r = mgr->apply(mgr); | ||
228 | if (r) | ||
229 | return r; | ||
230 | |||
231 | return size; | ||
232 | } | ||
233 | |||
234 | static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr, | ||
235 | char *buf) | ||
236 | { | ||
237 | struct omap_overlay_manager_info info; | ||
238 | |||
239 | mgr->get_manager_info(mgr, &info); | ||
240 | |||
241 | return snprintf(buf, PAGE_SIZE, "%d\n", info.trans_enabled); | ||
242 | } | ||
243 | |||
244 | static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr, | ||
245 | const char *buf, size_t size) | ||
246 | { | ||
247 | struct omap_overlay_manager_info info; | ||
248 | bool enable; | ||
249 | int r; | ||
250 | |||
251 | r = strtobool(buf, &enable); | ||
252 | if (r) | ||
253 | return r; | ||
254 | |||
255 | mgr->get_manager_info(mgr, &info); | ||
256 | |||
257 | info.trans_enabled = enable; | ||
258 | |||
259 | r = mgr->set_manager_info(mgr, &info); | ||
260 | if (r) | ||
261 | return r; | ||
262 | |||
263 | r = mgr->apply(mgr); | ||
264 | if (r) | ||
265 | return r; | ||
266 | |||
267 | return size; | ||
268 | } | ||
269 | |||
270 | static ssize_t manager_alpha_blending_enabled_show( | ||
271 | struct omap_overlay_manager *mgr, char *buf) | ||
272 | { | ||
273 | struct omap_overlay_manager_info info; | ||
274 | |||
275 | mgr->get_manager_info(mgr, &info); | ||
276 | |||
277 | WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)); | ||
278 | |||
279 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
280 | info.partial_alpha_enabled); | ||
281 | } | ||
282 | |||
283 | static ssize_t manager_alpha_blending_enabled_store( | ||
284 | struct omap_overlay_manager *mgr, | ||
285 | const char *buf, size_t size) | ||
286 | { | ||
287 | struct omap_overlay_manager_info info; | ||
288 | bool enable; | ||
289 | int r; | ||
290 | |||
291 | WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)); | ||
292 | |||
293 | r = strtobool(buf, &enable); | ||
294 | if (r) | ||
295 | return r; | ||
296 | |||
297 | mgr->get_manager_info(mgr, &info); | ||
298 | |||
299 | info.partial_alpha_enabled = enable; | ||
300 | |||
301 | r = mgr->set_manager_info(mgr, &info); | ||
302 | if (r) | ||
303 | return r; | ||
304 | |||
305 | r = mgr->apply(mgr); | ||
306 | if (r) | ||
307 | return r; | ||
308 | |||
309 | return size; | ||
310 | } | ||
311 | |||
312 | static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr, | ||
313 | char *buf) | ||
314 | { | ||
315 | struct omap_overlay_manager_info info; | ||
316 | |||
317 | mgr->get_manager_info(mgr, &info); | ||
318 | |||
319 | return snprintf(buf, PAGE_SIZE, "%d\n", info.cpr_enable); | ||
320 | } | ||
321 | |||
322 | static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr, | ||
323 | const char *buf, size_t size) | ||
324 | { | ||
325 | struct omap_overlay_manager_info info; | ||
326 | int r; | ||
327 | bool enable; | ||
328 | |||
329 | if (!dss_has_feature(FEAT_CPR)) | ||
330 | return -ENODEV; | ||
331 | |||
332 | r = strtobool(buf, &enable); | ||
333 | if (r) | ||
334 | return r; | ||
335 | |||
336 | mgr->get_manager_info(mgr, &info); | ||
337 | |||
338 | if (info.cpr_enable == enable) | ||
339 | return size; | ||
340 | |||
341 | info.cpr_enable = enable; | ||
342 | |||
343 | r = mgr->set_manager_info(mgr, &info); | ||
344 | if (r) | ||
345 | return r; | ||
346 | |||
347 | r = mgr->apply(mgr); | ||
348 | if (r) | ||
349 | return r; | ||
350 | |||
351 | return size; | ||
352 | } | ||
353 | |||
354 | static ssize_t manager_cpr_coef_show(struct omap_overlay_manager *mgr, | ||
355 | char *buf) | ||
356 | { | ||
357 | struct omap_overlay_manager_info info; | ||
358 | |||
359 | mgr->get_manager_info(mgr, &info); | ||
360 | |||
361 | return snprintf(buf, PAGE_SIZE, | ||
362 | "%d %d %d %d %d %d %d %d %d\n", | ||
363 | info.cpr_coefs.rr, | ||
364 | info.cpr_coefs.rg, | ||
365 | info.cpr_coefs.rb, | ||
366 | info.cpr_coefs.gr, | ||
367 | info.cpr_coefs.gg, | ||
368 | info.cpr_coefs.gb, | ||
369 | info.cpr_coefs.br, | ||
370 | info.cpr_coefs.bg, | ||
371 | info.cpr_coefs.bb); | ||
372 | } | ||
373 | |||
374 | static ssize_t manager_cpr_coef_store(struct omap_overlay_manager *mgr, | ||
375 | const char *buf, size_t size) | ||
376 | { | ||
377 | struct omap_overlay_manager_info info; | ||
378 | struct omap_dss_cpr_coefs coefs; | ||
379 | int r, i; | ||
380 | s16 *arr; | ||
381 | |||
382 | if (!dss_has_feature(FEAT_CPR)) | ||
383 | return -ENODEV; | ||
384 | |||
385 | if (sscanf(buf, "%hd %hd %hd %hd %hd %hd %hd %hd %hd", | ||
386 | &coefs.rr, &coefs.rg, &coefs.rb, | ||
387 | &coefs.gr, &coefs.gg, &coefs.gb, | ||
388 | &coefs.br, &coefs.bg, &coefs.bb) != 9) | ||
389 | return -EINVAL; | ||
390 | |||
391 | arr = (s16[]){ coefs.rr, coefs.rg, coefs.rb, | ||
392 | coefs.gr, coefs.gg, coefs.gb, | ||
393 | coefs.br, coefs.bg, coefs.bb }; | ||
394 | |||
395 | for (i = 0; i < 9; ++i) { | ||
396 | if (arr[i] < -512 || arr[i] > 511) | ||
397 | return -EINVAL; | ||
398 | } | ||
399 | |||
400 | mgr->get_manager_info(mgr, &info); | ||
401 | |||
402 | info.cpr_coefs = coefs; | ||
403 | |||
404 | r = mgr->set_manager_info(mgr, &info); | ||
405 | if (r) | ||
406 | return r; | ||
407 | |||
408 | r = mgr->apply(mgr); | ||
409 | if (r) | ||
410 | return r; | ||
411 | |||
412 | return size; | ||
413 | } | ||
414 | |||
415 | struct manager_attribute { | ||
416 | struct attribute attr; | ||
417 | ssize_t (*show)(struct omap_overlay_manager *, char *); | ||
418 | ssize_t (*store)(struct omap_overlay_manager *, const char *, size_t); | ||
419 | }; | ||
420 | |||
421 | #define MANAGER_ATTR(_name, _mode, _show, _store) \ | ||
422 | struct manager_attribute manager_attr_##_name = \ | ||
423 | __ATTR(_name, _mode, _show, _store) | ||
424 | |||
425 | static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL); | ||
426 | static MANAGER_ATTR(display, S_IRUGO|S_IWUSR, | ||
427 | manager_display_show, manager_display_store); | ||
428 | static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR, | ||
429 | manager_default_color_show, manager_default_color_store); | ||
430 | static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR, | ||
431 | manager_trans_key_type_show, manager_trans_key_type_store); | ||
432 | static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR, | ||
433 | manager_trans_key_value_show, manager_trans_key_value_store); | ||
434 | static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR, | ||
435 | manager_trans_key_enabled_show, | ||
436 | manager_trans_key_enabled_store); | ||
437 | static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR, | ||
438 | manager_alpha_blending_enabled_show, | ||
439 | manager_alpha_blending_enabled_store); | ||
440 | static MANAGER_ATTR(cpr_enable, S_IRUGO|S_IWUSR, | ||
441 | manager_cpr_enable_show, | ||
442 | manager_cpr_enable_store); | ||
443 | static MANAGER_ATTR(cpr_coef, S_IRUGO|S_IWUSR, | ||
444 | manager_cpr_coef_show, | ||
445 | manager_cpr_coef_store); | ||
446 | |||
447 | |||
448 | static struct attribute *manager_sysfs_attrs[] = { | ||
449 | &manager_attr_name.attr, | ||
450 | &manager_attr_display.attr, | ||
451 | &manager_attr_default_color.attr, | ||
452 | &manager_attr_trans_key_type.attr, | ||
453 | &manager_attr_trans_key_value.attr, | ||
454 | &manager_attr_trans_key_enabled.attr, | ||
455 | &manager_attr_alpha_blending_enabled.attr, | ||
456 | &manager_attr_cpr_enable.attr, | ||
457 | &manager_attr_cpr_coef.attr, | ||
458 | NULL | ||
459 | }; | ||
460 | |||
461 | static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr, | ||
462 | char *buf) | ||
463 | { | ||
464 | struct omap_overlay_manager *manager; | ||
465 | struct manager_attribute *manager_attr; | ||
466 | |||
467 | manager = container_of(kobj, struct omap_overlay_manager, kobj); | ||
468 | manager_attr = container_of(attr, struct manager_attribute, attr); | ||
469 | |||
470 | if (!manager_attr->show) | ||
471 | return -ENOENT; | ||
472 | |||
473 | return manager_attr->show(manager, buf); | ||
474 | } | ||
475 | |||
476 | static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr, | ||
477 | const char *buf, size_t size) | ||
478 | { | ||
479 | struct omap_overlay_manager *manager; | ||
480 | struct manager_attribute *manager_attr; | ||
481 | |||
482 | manager = container_of(kobj, struct omap_overlay_manager, kobj); | ||
483 | manager_attr = container_of(attr, struct manager_attribute, attr); | ||
484 | |||
485 | if (!manager_attr->store) | ||
486 | return -ENOENT; | ||
487 | |||
488 | return manager_attr->store(manager, buf, size); | ||
489 | } | ||
490 | |||
491 | static const struct sysfs_ops manager_sysfs_ops = { | ||
492 | .show = manager_attr_show, | ||
493 | .store = manager_attr_store, | ||
494 | }; | ||
495 | |||
496 | static struct kobj_type manager_ktype = { | ||
497 | .sysfs_ops = &manager_sysfs_ops, | ||
498 | .default_attrs = manager_sysfs_attrs, | ||
499 | }; | ||
500 | |||
501 | int dss_manager_kobj_init(struct omap_overlay_manager *mgr, | ||
502 | struct platform_device *pdev) | ||
503 | { | ||
504 | return kobject_init_and_add(&mgr->kobj, &manager_ktype, | ||
505 | &pdev->dev.kobj, "manager%d", mgr->id); | ||
506 | } | ||
507 | |||
508 | void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr) | ||
509 | { | ||
510 | kobject_del(&mgr->kobj); | ||
511 | kobject_put(&mgr->kobj); | ||
512 | } | ||
diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index 53710fadc82d..c54d2f620ce3 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c | |||
@@ -36,463 +36,15 @@ | |||
36 | static int num_managers; | 36 | static int num_managers; |
37 | static struct omap_overlay_manager *managers; | 37 | static struct omap_overlay_manager *managers; |
38 | 38 | ||
39 | static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf) | 39 | static inline struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_manager *mgr) |
40 | { | 40 | { |
41 | return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name); | 41 | return mgr->output ? mgr->output->device : NULL; |
42 | } | 42 | } |
43 | 43 | ||
44 | static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf) | ||
45 | { | ||
46 | return snprintf(buf, PAGE_SIZE, "%s\n", | ||
47 | mgr->device ? mgr->device->name : "<none>"); | ||
48 | } | ||
49 | |||
50 | static ssize_t manager_display_store(struct omap_overlay_manager *mgr, | ||
51 | const char *buf, size_t size) | ||
52 | { | ||
53 | int r = 0; | ||
54 | size_t len = size; | ||
55 | struct omap_dss_device *dssdev = NULL; | ||
56 | |||
57 | int match(struct omap_dss_device *dssdev, void *data) | ||
58 | { | ||
59 | const char *str = data; | ||
60 | return sysfs_streq(dssdev->name, str); | ||
61 | } | ||
62 | |||
63 | if (buf[size-1] == '\n') | ||
64 | --len; | ||
65 | |||
66 | if (len > 0) | ||
67 | dssdev = omap_dss_find_device((void *)buf, match); | ||
68 | |||
69 | if (len > 0 && dssdev == NULL) | ||
70 | return -EINVAL; | ||
71 | |||
72 | if (dssdev) | ||
73 | DSSDBG("display %s found\n", dssdev->name); | ||
74 | |||
75 | if (mgr->device) { | ||
76 | r = mgr->unset_device(mgr); | ||
77 | if (r) { | ||
78 | DSSERR("failed to unset display\n"); | ||
79 | goto put_device; | ||
80 | } | ||
81 | } | ||
82 | |||
83 | if (dssdev) { | ||
84 | r = mgr->set_device(mgr, dssdev); | ||
85 | if (r) { | ||
86 | DSSERR("failed to set manager\n"); | ||
87 | goto put_device; | ||
88 | } | ||
89 | |||
90 | r = mgr->apply(mgr); | ||
91 | if (r) { | ||
92 | DSSERR("failed to apply dispc config\n"); | ||
93 | goto put_device; | ||
94 | } | ||
95 | } | ||
96 | |||
97 | put_device: | ||
98 | if (dssdev) | ||
99 | omap_dss_put_device(dssdev); | ||
100 | |||
101 | return r ? r : size; | ||
102 | } | ||
103 | |||
104 | static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr, | ||
105 | char *buf) | ||
106 | { | ||
107 | struct omap_overlay_manager_info info; | ||
108 | |||
109 | mgr->get_manager_info(mgr, &info); | ||
110 | |||
111 | return snprintf(buf, PAGE_SIZE, "%#x\n", info.default_color); | ||
112 | } | ||
113 | |||
114 | static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr, | ||
115 | const char *buf, size_t size) | ||
116 | { | ||
117 | struct omap_overlay_manager_info info; | ||
118 | u32 color; | ||
119 | int r; | ||
120 | |||
121 | r = kstrtouint(buf, 0, &color); | ||
122 | if (r) | ||
123 | return r; | ||
124 | |||
125 | mgr->get_manager_info(mgr, &info); | ||
126 | |||
127 | info.default_color = color; | ||
128 | |||
129 | r = mgr->set_manager_info(mgr, &info); | ||
130 | if (r) | ||
131 | return r; | ||
132 | |||
133 | r = mgr->apply(mgr); | ||
134 | if (r) | ||
135 | return r; | ||
136 | |||
137 | return size; | ||
138 | } | ||
139 | |||
140 | static const char *trans_key_type_str[] = { | ||
141 | "gfx-destination", | ||
142 | "video-source", | ||
143 | }; | ||
144 | |||
145 | static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr, | ||
146 | char *buf) | ||
147 | { | ||
148 | enum omap_dss_trans_key_type key_type; | ||
149 | struct omap_overlay_manager_info info; | ||
150 | |||
151 | mgr->get_manager_info(mgr, &info); | ||
152 | |||
153 | key_type = info.trans_key_type; | ||
154 | BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str)); | ||
155 | |||
156 | return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]); | ||
157 | } | ||
158 | |||
159 | static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr, | ||
160 | const char *buf, size_t size) | ||
161 | { | ||
162 | enum omap_dss_trans_key_type key_type; | ||
163 | struct omap_overlay_manager_info info; | ||
164 | int r; | ||
165 | |||
166 | for (key_type = OMAP_DSS_COLOR_KEY_GFX_DST; | ||
167 | key_type < ARRAY_SIZE(trans_key_type_str); key_type++) { | ||
168 | if (sysfs_streq(buf, trans_key_type_str[key_type])) | ||
169 | break; | ||
170 | } | ||
171 | |||
172 | if (key_type == ARRAY_SIZE(trans_key_type_str)) | ||
173 | return -EINVAL; | ||
174 | |||
175 | mgr->get_manager_info(mgr, &info); | ||
176 | |||
177 | info.trans_key_type = key_type; | ||
178 | |||
179 | r = mgr->set_manager_info(mgr, &info); | ||
180 | if (r) | ||
181 | return r; | ||
182 | |||
183 | r = mgr->apply(mgr); | ||
184 | if (r) | ||
185 | return r; | ||
186 | |||
187 | return size; | ||
188 | } | ||
189 | |||
190 | static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr, | ||
191 | char *buf) | ||
192 | { | ||
193 | struct omap_overlay_manager_info info; | ||
194 | |||
195 | mgr->get_manager_info(mgr, &info); | ||
196 | |||
197 | return snprintf(buf, PAGE_SIZE, "%#x\n", info.trans_key); | ||
198 | } | ||
199 | |||
200 | static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr, | ||
201 | const char *buf, size_t size) | ||
202 | { | ||
203 | struct omap_overlay_manager_info info; | ||
204 | u32 key_value; | ||
205 | int r; | ||
206 | |||
207 | r = kstrtouint(buf, 0, &key_value); | ||
208 | if (r) | ||
209 | return r; | ||
210 | |||
211 | mgr->get_manager_info(mgr, &info); | ||
212 | |||
213 | info.trans_key = key_value; | ||
214 | |||
215 | r = mgr->set_manager_info(mgr, &info); | ||
216 | if (r) | ||
217 | return r; | ||
218 | |||
219 | r = mgr->apply(mgr); | ||
220 | if (r) | ||
221 | return r; | ||
222 | |||
223 | return size; | ||
224 | } | ||
225 | |||
226 | static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr, | ||
227 | char *buf) | ||
228 | { | ||
229 | struct omap_overlay_manager_info info; | ||
230 | |||
231 | mgr->get_manager_info(mgr, &info); | ||
232 | |||
233 | return snprintf(buf, PAGE_SIZE, "%d\n", info.trans_enabled); | ||
234 | } | ||
235 | |||
236 | static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr, | ||
237 | const char *buf, size_t size) | ||
238 | { | ||
239 | struct omap_overlay_manager_info info; | ||
240 | bool enable; | ||
241 | int r; | ||
242 | |||
243 | r = strtobool(buf, &enable); | ||
244 | if (r) | ||
245 | return r; | ||
246 | |||
247 | mgr->get_manager_info(mgr, &info); | ||
248 | |||
249 | info.trans_enabled = enable; | ||
250 | |||
251 | r = mgr->set_manager_info(mgr, &info); | ||
252 | if (r) | ||
253 | return r; | ||
254 | |||
255 | r = mgr->apply(mgr); | ||
256 | if (r) | ||
257 | return r; | ||
258 | |||
259 | return size; | ||
260 | } | ||
261 | |||
262 | static ssize_t manager_alpha_blending_enabled_show( | ||
263 | struct omap_overlay_manager *mgr, char *buf) | ||
264 | { | ||
265 | struct omap_overlay_manager_info info; | ||
266 | |||
267 | mgr->get_manager_info(mgr, &info); | ||
268 | |||
269 | WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)); | ||
270 | |||
271 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
272 | info.partial_alpha_enabled); | ||
273 | } | ||
274 | |||
275 | static ssize_t manager_alpha_blending_enabled_store( | ||
276 | struct omap_overlay_manager *mgr, | ||
277 | const char *buf, size_t size) | ||
278 | { | ||
279 | struct omap_overlay_manager_info info; | ||
280 | bool enable; | ||
281 | int r; | ||
282 | |||
283 | WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)); | ||
284 | |||
285 | r = strtobool(buf, &enable); | ||
286 | if (r) | ||
287 | return r; | ||
288 | |||
289 | mgr->get_manager_info(mgr, &info); | ||
290 | |||
291 | info.partial_alpha_enabled = enable; | ||
292 | |||
293 | r = mgr->set_manager_info(mgr, &info); | ||
294 | if (r) | ||
295 | return r; | ||
296 | |||
297 | r = mgr->apply(mgr); | ||
298 | if (r) | ||
299 | return r; | ||
300 | |||
301 | return size; | ||
302 | } | ||
303 | |||
304 | static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr, | ||
305 | char *buf) | ||
306 | { | ||
307 | struct omap_overlay_manager_info info; | ||
308 | |||
309 | mgr->get_manager_info(mgr, &info); | ||
310 | |||
311 | return snprintf(buf, PAGE_SIZE, "%d\n", info.cpr_enable); | ||
312 | } | ||
313 | |||
314 | static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr, | ||
315 | const char *buf, size_t size) | ||
316 | { | ||
317 | struct omap_overlay_manager_info info; | ||
318 | int r; | ||
319 | bool enable; | ||
320 | |||
321 | if (!dss_has_feature(FEAT_CPR)) | ||
322 | return -ENODEV; | ||
323 | |||
324 | r = strtobool(buf, &enable); | ||
325 | if (r) | ||
326 | return r; | ||
327 | |||
328 | mgr->get_manager_info(mgr, &info); | ||
329 | |||
330 | if (info.cpr_enable == enable) | ||
331 | return size; | ||
332 | |||
333 | info.cpr_enable = enable; | ||
334 | |||
335 | r = mgr->set_manager_info(mgr, &info); | ||
336 | if (r) | ||
337 | return r; | ||
338 | |||
339 | r = mgr->apply(mgr); | ||
340 | if (r) | ||
341 | return r; | ||
342 | |||
343 | return size; | ||
344 | } | ||
345 | |||
346 | static ssize_t manager_cpr_coef_show(struct omap_overlay_manager *mgr, | ||
347 | char *buf) | ||
348 | { | ||
349 | struct omap_overlay_manager_info info; | ||
350 | |||
351 | mgr->get_manager_info(mgr, &info); | ||
352 | |||
353 | return snprintf(buf, PAGE_SIZE, | ||
354 | "%d %d %d %d %d %d %d %d %d\n", | ||
355 | info.cpr_coefs.rr, | ||
356 | info.cpr_coefs.rg, | ||
357 | info.cpr_coefs.rb, | ||
358 | info.cpr_coefs.gr, | ||
359 | info.cpr_coefs.gg, | ||
360 | info.cpr_coefs.gb, | ||
361 | info.cpr_coefs.br, | ||
362 | info.cpr_coefs.bg, | ||
363 | info.cpr_coefs.bb); | ||
364 | } | ||
365 | |||
366 | static ssize_t manager_cpr_coef_store(struct omap_overlay_manager *mgr, | ||
367 | const char *buf, size_t size) | ||
368 | { | ||
369 | struct omap_overlay_manager_info info; | ||
370 | struct omap_dss_cpr_coefs coefs; | ||
371 | int r, i; | ||
372 | s16 *arr; | ||
373 | |||
374 | if (!dss_has_feature(FEAT_CPR)) | ||
375 | return -ENODEV; | ||
376 | |||
377 | if (sscanf(buf, "%hd %hd %hd %hd %hd %hd %hd %hd %hd", | ||
378 | &coefs.rr, &coefs.rg, &coefs.rb, | ||
379 | &coefs.gr, &coefs.gg, &coefs.gb, | ||
380 | &coefs.br, &coefs.bg, &coefs.bb) != 9) | ||
381 | return -EINVAL; | ||
382 | |||
383 | arr = (s16[]){ coefs.rr, coefs.rg, coefs.rb, | ||
384 | coefs.gr, coefs.gg, coefs.gb, | ||
385 | coefs.br, coefs.bg, coefs.bb }; | ||
386 | |||
387 | for (i = 0; i < 9; ++i) { | ||
388 | if (arr[i] < -512 || arr[i] > 511) | ||
389 | return -EINVAL; | ||
390 | } | ||
391 | |||
392 | mgr->get_manager_info(mgr, &info); | ||
393 | |||
394 | info.cpr_coefs = coefs; | ||
395 | |||
396 | r = mgr->set_manager_info(mgr, &info); | ||
397 | if (r) | ||
398 | return r; | ||
399 | |||
400 | r = mgr->apply(mgr); | ||
401 | if (r) | ||
402 | return r; | ||
403 | |||
404 | return size; | ||
405 | } | ||
406 | |||
407 | struct manager_attribute { | ||
408 | struct attribute attr; | ||
409 | ssize_t (*show)(struct omap_overlay_manager *, char *); | ||
410 | ssize_t (*store)(struct omap_overlay_manager *, const char *, size_t); | ||
411 | }; | ||
412 | |||
413 | #define MANAGER_ATTR(_name, _mode, _show, _store) \ | ||
414 | struct manager_attribute manager_attr_##_name = \ | ||
415 | __ATTR(_name, _mode, _show, _store) | ||
416 | |||
417 | static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL); | ||
418 | static MANAGER_ATTR(display, S_IRUGO|S_IWUSR, | ||
419 | manager_display_show, manager_display_store); | ||
420 | static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR, | ||
421 | manager_default_color_show, manager_default_color_store); | ||
422 | static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR, | ||
423 | manager_trans_key_type_show, manager_trans_key_type_store); | ||
424 | static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR, | ||
425 | manager_trans_key_value_show, manager_trans_key_value_store); | ||
426 | static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR, | ||
427 | manager_trans_key_enabled_show, | ||
428 | manager_trans_key_enabled_store); | ||
429 | static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR, | ||
430 | manager_alpha_blending_enabled_show, | ||
431 | manager_alpha_blending_enabled_store); | ||
432 | static MANAGER_ATTR(cpr_enable, S_IRUGO|S_IWUSR, | ||
433 | manager_cpr_enable_show, | ||
434 | manager_cpr_enable_store); | ||
435 | static MANAGER_ATTR(cpr_coef, S_IRUGO|S_IWUSR, | ||
436 | manager_cpr_coef_show, | ||
437 | manager_cpr_coef_store); | ||
438 | |||
439 | |||
440 | static struct attribute *manager_sysfs_attrs[] = { | ||
441 | &manager_attr_name.attr, | ||
442 | &manager_attr_display.attr, | ||
443 | &manager_attr_default_color.attr, | ||
444 | &manager_attr_trans_key_type.attr, | ||
445 | &manager_attr_trans_key_value.attr, | ||
446 | &manager_attr_trans_key_enabled.attr, | ||
447 | &manager_attr_alpha_blending_enabled.attr, | ||
448 | &manager_attr_cpr_enable.attr, | ||
449 | &manager_attr_cpr_coef.attr, | ||
450 | NULL | ||
451 | }; | ||
452 | |||
453 | static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr, | ||
454 | char *buf) | ||
455 | { | ||
456 | struct omap_overlay_manager *manager; | ||
457 | struct manager_attribute *manager_attr; | ||
458 | |||
459 | manager = container_of(kobj, struct omap_overlay_manager, kobj); | ||
460 | manager_attr = container_of(attr, struct manager_attribute, attr); | ||
461 | |||
462 | if (!manager_attr->show) | ||
463 | return -ENOENT; | ||
464 | |||
465 | return manager_attr->show(manager, buf); | ||
466 | } | ||
467 | |||
468 | static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr, | ||
469 | const char *buf, size_t size) | ||
470 | { | ||
471 | struct omap_overlay_manager *manager; | ||
472 | struct manager_attribute *manager_attr; | ||
473 | |||
474 | manager = container_of(kobj, struct omap_overlay_manager, kobj); | ||
475 | manager_attr = container_of(attr, struct manager_attribute, attr); | ||
476 | |||
477 | if (!manager_attr->store) | ||
478 | return -ENOENT; | ||
479 | |||
480 | return manager_attr->store(manager, buf, size); | ||
481 | } | ||
482 | |||
483 | static const struct sysfs_ops manager_sysfs_ops = { | ||
484 | .show = manager_attr_show, | ||
485 | .store = manager_attr_store, | ||
486 | }; | ||
487 | |||
488 | static struct kobj_type manager_ktype = { | ||
489 | .sysfs_ops = &manager_sysfs_ops, | ||
490 | .default_attrs = manager_sysfs_attrs, | ||
491 | }; | ||
492 | |||
493 | static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) | 44 | static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) |
494 | { | 45 | { |
495 | unsigned long timeout = msecs_to_jiffies(500); | 46 | unsigned long timeout = msecs_to_jiffies(500); |
47 | struct omap_dss_device *dssdev = mgr->get_device(mgr); | ||
496 | u32 irq; | 48 | u32 irq; |
497 | int r; | 49 | int r; |
498 | 50 | ||
@@ -500,9 +52,9 @@ static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) | |||
500 | if (r) | 52 | if (r) |
501 | return r; | 53 | return r; |
502 | 54 | ||
503 | if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC) | 55 | if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) |
504 | irq = DISPC_IRQ_EVSYNC_ODD; | 56 | irq = DISPC_IRQ_EVSYNC_ODD; |
505 | else if (mgr->device->type == OMAP_DISPLAY_TYPE_HDMI) | 57 | else if (dssdev->type == OMAP_DISPLAY_TYPE_HDMI) |
506 | irq = DISPC_IRQ_EVSYNC_EVEN; | 58 | irq = DISPC_IRQ_EVSYNC_EVEN; |
507 | else | 59 | else |
508 | irq = dispc_mgr_get_vsync_irq(mgr->id); | 60 | irq = dispc_mgr_get_vsync_irq(mgr->id); |
@@ -547,23 +99,24 @@ int dss_init_overlay_managers(struct platform_device *pdev) | |||
547 | break; | 99 | break; |
548 | } | 100 | } |
549 | 101 | ||
550 | mgr->set_device = &dss_mgr_set_device; | 102 | mgr->set_output = &dss_mgr_set_output; |
551 | mgr->unset_device = &dss_mgr_unset_device; | 103 | mgr->unset_output = &dss_mgr_unset_output; |
552 | mgr->apply = &omap_dss_mgr_apply; | 104 | mgr->apply = &omap_dss_mgr_apply; |
553 | mgr->set_manager_info = &dss_mgr_set_info; | 105 | mgr->set_manager_info = &dss_mgr_set_info; |
554 | mgr->get_manager_info = &dss_mgr_get_info; | 106 | mgr->get_manager_info = &dss_mgr_get_info; |
555 | mgr->wait_for_go = &dss_mgr_wait_for_go; | 107 | mgr->wait_for_go = &dss_mgr_wait_for_go; |
556 | mgr->wait_for_vsync = &dss_mgr_wait_for_vsync; | 108 | mgr->wait_for_vsync = &dss_mgr_wait_for_vsync; |
109 | mgr->get_device = &dss_mgr_get_device; | ||
557 | 110 | ||
558 | mgr->caps = 0; | 111 | mgr->caps = 0; |
559 | mgr->supported_displays = | 112 | mgr->supported_displays = |
560 | dss_feat_get_supported_displays(mgr->id); | 113 | dss_feat_get_supported_displays(mgr->id); |
114 | mgr->supported_outputs = | ||
115 | dss_feat_get_supported_outputs(mgr->id); | ||
561 | 116 | ||
562 | INIT_LIST_HEAD(&mgr->overlays); | 117 | INIT_LIST_HEAD(&mgr->overlays); |
563 | 118 | ||
564 | r = kobject_init_and_add(&mgr->kobj, &manager_ktype, | 119 | r = dss_manager_kobj_init(mgr, pdev); |
565 | &pdev->dev.kobj, "manager%d", i); | ||
566 | |||
567 | if (r) | 120 | if (r) |
568 | DSSERR("failed to create sysfs file\n"); | 121 | DSSERR("failed to create sysfs file\n"); |
569 | } | 122 | } |
@@ -577,9 +130,7 @@ void dss_uninit_overlay_managers(struct platform_device *pdev) | |||
577 | 130 | ||
578 | for (i = 0; i < num_managers; ++i) { | 131 | for (i = 0; i < num_managers; ++i) { |
579 | struct omap_overlay_manager *mgr = &managers[i]; | 132 | struct omap_overlay_manager *mgr = &managers[i]; |
580 | 133 | dss_manager_kobj_uninit(mgr); | |
581 | kobject_del(&mgr->kobj); | ||
582 | kobject_put(&mgr->kobj); | ||
583 | } | 134 | } |
584 | 135 | ||
585 | kfree(managers); | 136 | kfree(managers); |
diff --git a/drivers/video/omap2/dss/output.c b/drivers/video/omap2/dss/output.c new file mode 100644 index 000000000000..813f26682b7a --- /dev/null +++ b/drivers/video/omap2/dss/output.c | |||
@@ -0,0 +1,148 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 Texas Instruments Ltd | ||
3 | * Author: Archit Taneja <archit@ti.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License version 2 as published by | ||
7 | * the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/slab.h> | ||
22 | |||
23 | #include <video/omapdss.h> | ||
24 | |||
25 | #include "dss.h" | ||
26 | |||
27 | static LIST_HEAD(output_list); | ||
28 | static DEFINE_MUTEX(output_lock); | ||
29 | |||
30 | int omapdss_output_set_device(struct omap_dss_output *out, | ||
31 | struct omap_dss_device *dssdev) | ||
32 | { | ||
33 | int r; | ||
34 | |||
35 | mutex_lock(&output_lock); | ||
36 | |||
37 | if (out->device) { | ||
38 | DSSERR("output already has device %s connected to it\n", | ||
39 | out->device->name); | ||
40 | r = -EINVAL; | ||
41 | goto err; | ||
42 | } | ||
43 | |||
44 | if (out->type != dssdev->type) { | ||
45 | DSSERR("output type and display type don't match\n"); | ||
46 | r = -EINVAL; | ||
47 | goto err; | ||
48 | } | ||
49 | |||
50 | out->device = dssdev; | ||
51 | dssdev->output = out; | ||
52 | |||
53 | mutex_unlock(&output_lock); | ||
54 | |||
55 | return 0; | ||
56 | err: | ||
57 | mutex_unlock(&output_lock); | ||
58 | |||
59 | return r; | ||
60 | } | ||
61 | EXPORT_SYMBOL(omapdss_output_set_device); | ||
62 | |||
63 | int omapdss_output_unset_device(struct omap_dss_output *out) | ||
64 | { | ||
65 | int r; | ||
66 | |||
67 | mutex_lock(&output_lock); | ||
68 | |||
69 | if (!out->device) { | ||
70 | DSSERR("output doesn't have a device connected to it\n"); | ||
71 | r = -EINVAL; | ||
72 | goto err; | ||
73 | } | ||
74 | |||
75 | if (out->device->state != OMAP_DSS_DISPLAY_DISABLED) { | ||
76 | DSSERR("device %s is not disabled, cannot unset device\n", | ||
77 | out->device->name); | ||
78 | r = -EINVAL; | ||
79 | goto err; | ||
80 | } | ||
81 | |||
82 | out->device->output = NULL; | ||
83 | out->device = NULL; | ||
84 | |||
85 | mutex_unlock(&output_lock); | ||
86 | |||
87 | return 0; | ||
88 | err: | ||
89 | mutex_unlock(&output_lock); | ||
90 | |||
91 | return r; | ||
92 | } | ||
93 | EXPORT_SYMBOL(omapdss_output_unset_device); | ||
94 | |||
95 | void dss_register_output(struct omap_dss_output *out) | ||
96 | { | ||
97 | list_add_tail(&out->list, &output_list); | ||
98 | } | ||
99 | |||
100 | void dss_unregister_output(struct omap_dss_output *out) | ||
101 | { | ||
102 | list_del(&out->list); | ||
103 | } | ||
104 | |||
105 | struct omap_dss_output *omap_dss_get_output(enum omap_dss_output_id id) | ||
106 | { | ||
107 | struct omap_dss_output *out; | ||
108 | |||
109 | list_for_each_entry(out, &output_list, list) { | ||
110 | if (out->id == id) | ||
111 | return out; | ||
112 | } | ||
113 | |||
114 | return NULL; | ||
115 | } | ||
116 | |||
117 | struct omap_dss_output *omapdss_get_output_from_dssdev(struct omap_dss_device *dssdev) | ||
118 | { | ||
119 | struct omap_dss_output *out = NULL; | ||
120 | enum omap_dss_output_id id; | ||
121 | |||
122 | switch (dssdev->type) { | ||
123 | case OMAP_DISPLAY_TYPE_DPI: | ||
124 | out = omap_dss_get_output(OMAP_DSS_OUTPUT_DPI); | ||
125 | break; | ||
126 | case OMAP_DISPLAY_TYPE_DBI: | ||
127 | out = omap_dss_get_output(OMAP_DSS_OUTPUT_DBI); | ||
128 | break; | ||
129 | case OMAP_DISPLAY_TYPE_SDI: | ||
130 | out = omap_dss_get_output(OMAP_DSS_OUTPUT_SDI); | ||
131 | break; | ||
132 | case OMAP_DISPLAY_TYPE_VENC: | ||
133 | out = omap_dss_get_output(OMAP_DSS_OUTPUT_VENC); | ||
134 | break; | ||
135 | case OMAP_DISPLAY_TYPE_HDMI: | ||
136 | out = omap_dss_get_output(OMAP_DSS_OUTPUT_HDMI); | ||
137 | break; | ||
138 | case OMAP_DISPLAY_TYPE_DSI: | ||
139 | id = dssdev->phy.dsi.module == 0 ? OMAP_DSS_OUTPUT_DSI1 : | ||
140 | OMAP_DSS_OUTPUT_DSI2; | ||
141 | out = omap_dss_get_output(id); | ||
142 | break; | ||
143 | default: | ||
144 | break; | ||
145 | } | ||
146 | |||
147 | return out; | ||
148 | } | ||
diff --git a/drivers/video/omap2/dss/overlay-sysfs.c b/drivers/video/omap2/dss/overlay-sysfs.c new file mode 100644 index 000000000000..4cc5ddebfb34 --- /dev/null +++ b/drivers/video/omap2/dss/overlay-sysfs.c | |||
@@ -0,0 +1,456 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Nokia Corporation | ||
3 | * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> | ||
4 | * | ||
5 | * Some code and ideas taken from drivers/video/omap/ driver | ||
6 | * by Imre Deak. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License version 2 as published by | ||
10 | * the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along with | ||
18 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
19 | */ | ||
20 | |||
21 | #define DSS_SUBSYS_NAME "OVERLAY" | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/err.h> | ||
25 | #include <linux/sysfs.h> | ||
26 | #include <linux/kobject.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | |||
29 | #include <video/omapdss.h> | ||
30 | |||
31 | #include "dss.h" | ||
32 | #include "dss_features.h" | ||
33 | |||
34 | static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf) | ||
35 | { | ||
36 | return snprintf(buf, PAGE_SIZE, "%s\n", ovl->name); | ||
37 | } | ||
38 | |||
39 | static ssize_t overlay_manager_show(struct omap_overlay *ovl, char *buf) | ||
40 | { | ||
41 | return snprintf(buf, PAGE_SIZE, "%s\n", | ||
42 | ovl->manager ? ovl->manager->name : "<none>"); | ||
43 | } | ||
44 | |||
45 | static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf, | ||
46 | size_t size) | ||
47 | { | ||
48 | int i, r; | ||
49 | struct omap_overlay_manager *mgr = NULL; | ||
50 | struct omap_overlay_manager *old_mgr; | ||
51 | int len = size; | ||
52 | |||
53 | if (buf[size-1] == '\n') | ||
54 | --len; | ||
55 | |||
56 | if (len > 0) { | ||
57 | for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { | ||
58 | mgr = omap_dss_get_overlay_manager(i); | ||
59 | |||
60 | if (sysfs_streq(buf, mgr->name)) | ||
61 | break; | ||
62 | |||
63 | mgr = NULL; | ||
64 | } | ||
65 | } | ||
66 | |||
67 | if (len > 0 && mgr == NULL) | ||
68 | return -EINVAL; | ||
69 | |||
70 | if (mgr) | ||
71 | DSSDBG("manager %s found\n", mgr->name); | ||
72 | |||
73 | if (mgr == ovl->manager) | ||
74 | return size; | ||
75 | |||
76 | old_mgr = ovl->manager; | ||
77 | |||
78 | r = dispc_runtime_get(); | ||
79 | if (r) | ||
80 | return r; | ||
81 | |||
82 | /* detach old manager */ | ||
83 | if (old_mgr) { | ||
84 | r = ovl->unset_manager(ovl); | ||
85 | if (r) { | ||
86 | DSSERR("detach failed\n"); | ||
87 | goto err; | ||
88 | } | ||
89 | |||
90 | r = old_mgr->apply(old_mgr); | ||
91 | if (r) | ||
92 | goto err; | ||
93 | } | ||
94 | |||
95 | if (mgr) { | ||
96 | r = ovl->set_manager(ovl, mgr); | ||
97 | if (r) { | ||
98 | DSSERR("Failed to attach overlay\n"); | ||
99 | goto err; | ||
100 | } | ||
101 | |||
102 | r = mgr->apply(mgr); | ||
103 | if (r) | ||
104 | goto err; | ||
105 | } | ||
106 | |||
107 | dispc_runtime_put(); | ||
108 | |||
109 | return size; | ||
110 | |||
111 | err: | ||
112 | dispc_runtime_put(); | ||
113 | return r; | ||
114 | } | ||
115 | |||
116 | static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf) | ||
117 | { | ||
118 | struct omap_overlay_info info; | ||
119 | |||
120 | ovl->get_overlay_info(ovl, &info); | ||
121 | |||
122 | return snprintf(buf, PAGE_SIZE, "%d,%d\n", | ||
123 | info.width, info.height); | ||
124 | } | ||
125 | |||
126 | static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf) | ||
127 | { | ||
128 | struct omap_overlay_info info; | ||
129 | |||
130 | ovl->get_overlay_info(ovl, &info); | ||
131 | |||
132 | return snprintf(buf, PAGE_SIZE, "%d\n", info.screen_width); | ||
133 | } | ||
134 | |||
135 | static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf) | ||
136 | { | ||
137 | struct omap_overlay_info info; | ||
138 | |||
139 | ovl->get_overlay_info(ovl, &info); | ||
140 | |||
141 | return snprintf(buf, PAGE_SIZE, "%d,%d\n", | ||
142 | info.pos_x, info.pos_y); | ||
143 | } | ||
144 | |||
145 | static ssize_t overlay_position_store(struct omap_overlay *ovl, | ||
146 | const char *buf, size_t size) | ||
147 | { | ||
148 | int r; | ||
149 | char *last; | ||
150 | struct omap_overlay_info info; | ||
151 | |||
152 | ovl->get_overlay_info(ovl, &info); | ||
153 | |||
154 | info.pos_x = simple_strtoul(buf, &last, 10); | ||
155 | ++last; | ||
156 | if (last - buf >= size) | ||
157 | return -EINVAL; | ||
158 | |||
159 | info.pos_y = simple_strtoul(last, &last, 10); | ||
160 | |||
161 | r = ovl->set_overlay_info(ovl, &info); | ||
162 | if (r) | ||
163 | return r; | ||
164 | |||
165 | if (ovl->manager) { | ||
166 | r = ovl->manager->apply(ovl->manager); | ||
167 | if (r) | ||
168 | return r; | ||
169 | } | ||
170 | |||
171 | return size; | ||
172 | } | ||
173 | |||
174 | static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf) | ||
175 | { | ||
176 | struct omap_overlay_info info; | ||
177 | |||
178 | ovl->get_overlay_info(ovl, &info); | ||
179 | |||
180 | return snprintf(buf, PAGE_SIZE, "%d,%d\n", | ||
181 | info.out_width, info.out_height); | ||
182 | } | ||
183 | |||
184 | static ssize_t overlay_output_size_store(struct omap_overlay *ovl, | ||
185 | const char *buf, size_t size) | ||
186 | { | ||
187 | int r; | ||
188 | char *last; | ||
189 | struct omap_overlay_info info; | ||
190 | |||
191 | ovl->get_overlay_info(ovl, &info); | ||
192 | |||
193 | info.out_width = simple_strtoul(buf, &last, 10); | ||
194 | ++last; | ||
195 | if (last - buf >= size) | ||
196 | return -EINVAL; | ||
197 | |||
198 | info.out_height = simple_strtoul(last, &last, 10); | ||
199 | |||
200 | r = ovl->set_overlay_info(ovl, &info); | ||
201 | if (r) | ||
202 | return r; | ||
203 | |||
204 | if (ovl->manager) { | ||
205 | r = ovl->manager->apply(ovl->manager); | ||
206 | if (r) | ||
207 | return r; | ||
208 | } | ||
209 | |||
210 | return size; | ||
211 | } | ||
212 | |||
213 | static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf) | ||
214 | { | ||
215 | return snprintf(buf, PAGE_SIZE, "%d\n", ovl->is_enabled(ovl)); | ||
216 | } | ||
217 | |||
218 | static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf, | ||
219 | size_t size) | ||
220 | { | ||
221 | int r; | ||
222 | bool enable; | ||
223 | |||
224 | r = strtobool(buf, &enable); | ||
225 | if (r) | ||
226 | return r; | ||
227 | |||
228 | if (enable) | ||
229 | r = ovl->enable(ovl); | ||
230 | else | ||
231 | r = ovl->disable(ovl); | ||
232 | |||
233 | if (r) | ||
234 | return r; | ||
235 | |||
236 | return size; | ||
237 | } | ||
238 | |||
239 | static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf) | ||
240 | { | ||
241 | struct omap_overlay_info info; | ||
242 | |||
243 | ovl->get_overlay_info(ovl, &info); | ||
244 | |||
245 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
246 | info.global_alpha); | ||
247 | } | ||
248 | |||
249 | static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl, | ||
250 | const char *buf, size_t size) | ||
251 | { | ||
252 | int r; | ||
253 | u8 alpha; | ||
254 | struct omap_overlay_info info; | ||
255 | |||
256 | if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0) | ||
257 | return -ENODEV; | ||
258 | |||
259 | r = kstrtou8(buf, 0, &alpha); | ||
260 | if (r) | ||
261 | return r; | ||
262 | |||
263 | ovl->get_overlay_info(ovl, &info); | ||
264 | |||
265 | info.global_alpha = alpha; | ||
266 | |||
267 | r = ovl->set_overlay_info(ovl, &info); | ||
268 | if (r) | ||
269 | return r; | ||
270 | |||
271 | if (ovl->manager) { | ||
272 | r = ovl->manager->apply(ovl->manager); | ||
273 | if (r) | ||
274 | return r; | ||
275 | } | ||
276 | |||
277 | return size; | ||
278 | } | ||
279 | |||
280 | static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl, | ||
281 | char *buf) | ||
282 | { | ||
283 | struct omap_overlay_info info; | ||
284 | |||
285 | ovl->get_overlay_info(ovl, &info); | ||
286 | |||
287 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
288 | info.pre_mult_alpha); | ||
289 | } | ||
290 | |||
291 | static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl, | ||
292 | const char *buf, size_t size) | ||
293 | { | ||
294 | int r; | ||
295 | u8 alpha; | ||
296 | struct omap_overlay_info info; | ||
297 | |||
298 | if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0) | ||
299 | return -ENODEV; | ||
300 | |||
301 | r = kstrtou8(buf, 0, &alpha); | ||
302 | if (r) | ||
303 | return r; | ||
304 | |||
305 | ovl->get_overlay_info(ovl, &info); | ||
306 | |||
307 | info.pre_mult_alpha = alpha; | ||
308 | |||
309 | r = ovl->set_overlay_info(ovl, &info); | ||
310 | if (r) | ||
311 | return r; | ||
312 | |||
313 | if (ovl->manager) { | ||
314 | r = ovl->manager->apply(ovl->manager); | ||
315 | if (r) | ||
316 | return r; | ||
317 | } | ||
318 | |||
319 | return size; | ||
320 | } | ||
321 | |||
322 | static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf) | ||
323 | { | ||
324 | struct omap_overlay_info info; | ||
325 | |||
326 | ovl->get_overlay_info(ovl, &info); | ||
327 | |||
328 | return snprintf(buf, PAGE_SIZE, "%d\n", info.zorder); | ||
329 | } | ||
330 | |||
331 | static ssize_t overlay_zorder_store(struct omap_overlay *ovl, | ||
332 | const char *buf, size_t size) | ||
333 | { | ||
334 | int r; | ||
335 | u8 zorder; | ||
336 | struct omap_overlay_info info; | ||
337 | |||
338 | if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0) | ||
339 | return -ENODEV; | ||
340 | |||
341 | r = kstrtou8(buf, 0, &zorder); | ||
342 | if (r) | ||
343 | return r; | ||
344 | |||
345 | ovl->get_overlay_info(ovl, &info); | ||
346 | |||
347 | info.zorder = zorder; | ||
348 | |||
349 | r = ovl->set_overlay_info(ovl, &info); | ||
350 | if (r) | ||
351 | return r; | ||
352 | |||
353 | if (ovl->manager) { | ||
354 | r = ovl->manager->apply(ovl->manager); | ||
355 | if (r) | ||
356 | return r; | ||
357 | } | ||
358 | |||
359 | return size; | ||
360 | } | ||
361 | |||
362 | struct overlay_attribute { | ||
363 | struct attribute attr; | ||
364 | ssize_t (*show)(struct omap_overlay *, char *); | ||
365 | ssize_t (*store)(struct omap_overlay *, const char *, size_t); | ||
366 | }; | ||
367 | |||
368 | #define OVERLAY_ATTR(_name, _mode, _show, _store) \ | ||
369 | struct overlay_attribute overlay_attr_##_name = \ | ||
370 | __ATTR(_name, _mode, _show, _store) | ||
371 | |||
372 | static OVERLAY_ATTR(name, S_IRUGO, overlay_name_show, NULL); | ||
373 | static OVERLAY_ATTR(manager, S_IRUGO|S_IWUSR, | ||
374 | overlay_manager_show, overlay_manager_store); | ||
375 | static OVERLAY_ATTR(input_size, S_IRUGO, overlay_input_size_show, NULL); | ||
376 | static OVERLAY_ATTR(screen_width, S_IRUGO, overlay_screen_width_show, NULL); | ||
377 | static OVERLAY_ATTR(position, S_IRUGO|S_IWUSR, | ||
378 | overlay_position_show, overlay_position_store); | ||
379 | static OVERLAY_ATTR(output_size, S_IRUGO|S_IWUSR, | ||
380 | overlay_output_size_show, overlay_output_size_store); | ||
381 | static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR, | ||
382 | overlay_enabled_show, overlay_enabled_store); | ||
383 | static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR, | ||
384 | overlay_global_alpha_show, overlay_global_alpha_store); | ||
385 | static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR, | ||
386 | overlay_pre_mult_alpha_show, | ||
387 | overlay_pre_mult_alpha_store); | ||
388 | static OVERLAY_ATTR(zorder, S_IRUGO|S_IWUSR, | ||
389 | overlay_zorder_show, overlay_zorder_store); | ||
390 | |||
391 | static struct attribute *overlay_sysfs_attrs[] = { | ||
392 | &overlay_attr_name.attr, | ||
393 | &overlay_attr_manager.attr, | ||
394 | &overlay_attr_input_size.attr, | ||
395 | &overlay_attr_screen_width.attr, | ||
396 | &overlay_attr_position.attr, | ||
397 | &overlay_attr_output_size.attr, | ||
398 | &overlay_attr_enabled.attr, | ||
399 | &overlay_attr_global_alpha.attr, | ||
400 | &overlay_attr_pre_mult_alpha.attr, | ||
401 | &overlay_attr_zorder.attr, | ||
402 | NULL | ||
403 | }; | ||
404 | |||
405 | static ssize_t overlay_attr_show(struct kobject *kobj, struct attribute *attr, | ||
406 | char *buf) | ||
407 | { | ||
408 | struct omap_overlay *overlay; | ||
409 | struct overlay_attribute *overlay_attr; | ||
410 | |||
411 | overlay = container_of(kobj, struct omap_overlay, kobj); | ||
412 | overlay_attr = container_of(attr, struct overlay_attribute, attr); | ||
413 | |||
414 | if (!overlay_attr->show) | ||
415 | return -ENOENT; | ||
416 | |||
417 | return overlay_attr->show(overlay, buf); | ||
418 | } | ||
419 | |||
420 | static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr, | ||
421 | const char *buf, size_t size) | ||
422 | { | ||
423 | struct omap_overlay *overlay; | ||
424 | struct overlay_attribute *overlay_attr; | ||
425 | |||
426 | overlay = container_of(kobj, struct omap_overlay, kobj); | ||
427 | overlay_attr = container_of(attr, struct overlay_attribute, attr); | ||
428 | |||
429 | if (!overlay_attr->store) | ||
430 | return -ENOENT; | ||
431 | |||
432 | return overlay_attr->store(overlay, buf, size); | ||
433 | } | ||
434 | |||
435 | static const struct sysfs_ops overlay_sysfs_ops = { | ||
436 | .show = overlay_attr_show, | ||
437 | .store = overlay_attr_store, | ||
438 | }; | ||
439 | |||
440 | static struct kobj_type overlay_ktype = { | ||
441 | .sysfs_ops = &overlay_sysfs_ops, | ||
442 | .default_attrs = overlay_sysfs_attrs, | ||
443 | }; | ||
444 | |||
445 | int dss_overlay_kobj_init(struct omap_overlay *ovl, | ||
446 | struct platform_device *pdev) | ||
447 | { | ||
448 | return kobject_init_and_add(&ovl->kobj, &overlay_ktype, | ||
449 | &pdev->dev.kobj, "overlay%d", ovl->id); | ||
450 | } | ||
451 | |||
452 | void dss_overlay_kobj_uninit(struct omap_overlay *ovl) | ||
453 | { | ||
454 | kobject_del(&ovl->kobj); | ||
455 | kobject_put(&ovl->kobj); | ||
456 | } | ||
diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c index 952c6fad9a81..45f4994bc6b0 100644 --- a/drivers/video/omap2/dss/overlay.c +++ b/drivers/video/omap2/dss/overlay.c | |||
@@ -26,13 +26,11 @@ | |||
26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | #include <linux/err.h> | 27 | #include <linux/err.h> |
28 | #include <linux/sysfs.h> | 28 | #include <linux/sysfs.h> |
29 | #include <linux/kobject.h> | ||
30 | #include <linux/platform_device.h> | 29 | #include <linux/platform_device.h> |
31 | #include <linux/delay.h> | 30 | #include <linux/delay.h> |
32 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
33 | 32 | ||
34 | #include <video/omapdss.h> | 33 | #include <video/omapdss.h> |
35 | #include <plat/cpu.h> | ||
36 | 34 | ||
37 | #include "dss.h" | 35 | #include "dss.h" |
38 | #include "dss_features.h" | 36 | #include "dss_features.h" |
@@ -40,417 +38,13 @@ | |||
40 | static int num_overlays; | 38 | static int num_overlays; |
41 | static struct omap_overlay *overlays; | 39 | static struct omap_overlay *overlays; |
42 | 40 | ||
43 | static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf) | 41 | static inline struct omap_dss_device *dss_ovl_get_device(struct omap_overlay *ovl) |
44 | { | 42 | { |
45 | return snprintf(buf, PAGE_SIZE, "%s\n", ovl->name); | 43 | return ovl->manager ? |
44 | (ovl->manager->output ? ovl->manager->output->device : NULL) : | ||
45 | NULL; | ||
46 | } | 46 | } |
47 | 47 | ||
48 | static ssize_t overlay_manager_show(struct omap_overlay *ovl, char *buf) | ||
49 | { | ||
50 | return snprintf(buf, PAGE_SIZE, "%s\n", | ||
51 | ovl->manager ? ovl->manager->name : "<none>"); | ||
52 | } | ||
53 | |||
54 | static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf, | ||
55 | size_t size) | ||
56 | { | ||
57 | int i, r; | ||
58 | struct omap_overlay_manager *mgr = NULL; | ||
59 | struct omap_overlay_manager *old_mgr; | ||
60 | int len = size; | ||
61 | |||
62 | if (buf[size-1] == '\n') | ||
63 | --len; | ||
64 | |||
65 | if (len > 0) { | ||
66 | for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { | ||
67 | mgr = omap_dss_get_overlay_manager(i); | ||
68 | |||
69 | if (sysfs_streq(buf, mgr->name)) | ||
70 | break; | ||
71 | |||
72 | mgr = NULL; | ||
73 | } | ||
74 | } | ||
75 | |||
76 | if (len > 0 && mgr == NULL) | ||
77 | return -EINVAL; | ||
78 | |||
79 | if (mgr) | ||
80 | DSSDBG("manager %s found\n", mgr->name); | ||
81 | |||
82 | if (mgr == ovl->manager) | ||
83 | return size; | ||
84 | |||
85 | old_mgr = ovl->manager; | ||
86 | |||
87 | r = dispc_runtime_get(); | ||
88 | if (r) | ||
89 | return r; | ||
90 | |||
91 | /* detach old manager */ | ||
92 | if (old_mgr) { | ||
93 | r = ovl->unset_manager(ovl); | ||
94 | if (r) { | ||
95 | DSSERR("detach failed\n"); | ||
96 | goto err; | ||
97 | } | ||
98 | |||
99 | r = old_mgr->apply(old_mgr); | ||
100 | if (r) | ||
101 | goto err; | ||
102 | } | ||
103 | |||
104 | if (mgr) { | ||
105 | r = ovl->set_manager(ovl, mgr); | ||
106 | if (r) { | ||
107 | DSSERR("Failed to attach overlay\n"); | ||
108 | goto err; | ||
109 | } | ||
110 | |||
111 | r = mgr->apply(mgr); | ||
112 | if (r) | ||
113 | goto err; | ||
114 | } | ||
115 | |||
116 | dispc_runtime_put(); | ||
117 | |||
118 | return size; | ||
119 | |||
120 | err: | ||
121 | dispc_runtime_put(); | ||
122 | return r; | ||
123 | } | ||
124 | |||
125 | static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf) | ||
126 | { | ||
127 | struct omap_overlay_info info; | ||
128 | |||
129 | ovl->get_overlay_info(ovl, &info); | ||
130 | |||
131 | return snprintf(buf, PAGE_SIZE, "%d,%d\n", | ||
132 | info.width, info.height); | ||
133 | } | ||
134 | |||
135 | static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf) | ||
136 | { | ||
137 | struct omap_overlay_info info; | ||
138 | |||
139 | ovl->get_overlay_info(ovl, &info); | ||
140 | |||
141 | return snprintf(buf, PAGE_SIZE, "%d\n", info.screen_width); | ||
142 | } | ||
143 | |||
144 | static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf) | ||
145 | { | ||
146 | struct omap_overlay_info info; | ||
147 | |||
148 | ovl->get_overlay_info(ovl, &info); | ||
149 | |||
150 | return snprintf(buf, PAGE_SIZE, "%d,%d\n", | ||
151 | info.pos_x, info.pos_y); | ||
152 | } | ||
153 | |||
154 | static ssize_t overlay_position_store(struct omap_overlay *ovl, | ||
155 | const char *buf, size_t size) | ||
156 | { | ||
157 | int r; | ||
158 | char *last; | ||
159 | struct omap_overlay_info info; | ||
160 | |||
161 | ovl->get_overlay_info(ovl, &info); | ||
162 | |||
163 | info.pos_x = simple_strtoul(buf, &last, 10); | ||
164 | ++last; | ||
165 | if (last - buf >= size) | ||
166 | return -EINVAL; | ||
167 | |||
168 | info.pos_y = simple_strtoul(last, &last, 10); | ||
169 | |||
170 | r = ovl->set_overlay_info(ovl, &info); | ||
171 | if (r) | ||
172 | return r; | ||
173 | |||
174 | if (ovl->manager) { | ||
175 | r = ovl->manager->apply(ovl->manager); | ||
176 | if (r) | ||
177 | return r; | ||
178 | } | ||
179 | |||
180 | return size; | ||
181 | } | ||
182 | |||
183 | static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf) | ||
184 | { | ||
185 | struct omap_overlay_info info; | ||
186 | |||
187 | ovl->get_overlay_info(ovl, &info); | ||
188 | |||
189 | return snprintf(buf, PAGE_SIZE, "%d,%d\n", | ||
190 | info.out_width, info.out_height); | ||
191 | } | ||
192 | |||
193 | static ssize_t overlay_output_size_store(struct omap_overlay *ovl, | ||
194 | const char *buf, size_t size) | ||
195 | { | ||
196 | int r; | ||
197 | char *last; | ||
198 | struct omap_overlay_info info; | ||
199 | |||
200 | ovl->get_overlay_info(ovl, &info); | ||
201 | |||
202 | info.out_width = simple_strtoul(buf, &last, 10); | ||
203 | ++last; | ||
204 | if (last - buf >= size) | ||
205 | return -EINVAL; | ||
206 | |||
207 | info.out_height = simple_strtoul(last, &last, 10); | ||
208 | |||
209 | r = ovl->set_overlay_info(ovl, &info); | ||
210 | if (r) | ||
211 | return r; | ||
212 | |||
213 | if (ovl->manager) { | ||
214 | r = ovl->manager->apply(ovl->manager); | ||
215 | if (r) | ||
216 | return r; | ||
217 | } | ||
218 | |||
219 | return size; | ||
220 | } | ||
221 | |||
222 | static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf) | ||
223 | { | ||
224 | return snprintf(buf, PAGE_SIZE, "%d\n", ovl->is_enabled(ovl)); | ||
225 | } | ||
226 | |||
227 | static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf, | ||
228 | size_t size) | ||
229 | { | ||
230 | int r; | ||
231 | bool enable; | ||
232 | |||
233 | r = strtobool(buf, &enable); | ||
234 | if (r) | ||
235 | return r; | ||
236 | |||
237 | if (enable) | ||
238 | r = ovl->enable(ovl); | ||
239 | else | ||
240 | r = ovl->disable(ovl); | ||
241 | |||
242 | if (r) | ||
243 | return r; | ||
244 | |||
245 | return size; | ||
246 | } | ||
247 | |||
248 | static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf) | ||
249 | { | ||
250 | struct omap_overlay_info info; | ||
251 | |||
252 | ovl->get_overlay_info(ovl, &info); | ||
253 | |||
254 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
255 | info.global_alpha); | ||
256 | } | ||
257 | |||
258 | static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl, | ||
259 | const char *buf, size_t size) | ||
260 | { | ||
261 | int r; | ||
262 | u8 alpha; | ||
263 | struct omap_overlay_info info; | ||
264 | |||
265 | if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0) | ||
266 | return -ENODEV; | ||
267 | |||
268 | r = kstrtou8(buf, 0, &alpha); | ||
269 | if (r) | ||
270 | return r; | ||
271 | |||
272 | ovl->get_overlay_info(ovl, &info); | ||
273 | |||
274 | info.global_alpha = alpha; | ||
275 | |||
276 | r = ovl->set_overlay_info(ovl, &info); | ||
277 | if (r) | ||
278 | return r; | ||
279 | |||
280 | if (ovl->manager) { | ||
281 | r = ovl->manager->apply(ovl->manager); | ||
282 | if (r) | ||
283 | return r; | ||
284 | } | ||
285 | |||
286 | return size; | ||
287 | } | ||
288 | |||
289 | static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl, | ||
290 | char *buf) | ||
291 | { | ||
292 | struct omap_overlay_info info; | ||
293 | |||
294 | ovl->get_overlay_info(ovl, &info); | ||
295 | |||
296 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
297 | info.pre_mult_alpha); | ||
298 | } | ||
299 | |||
300 | static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl, | ||
301 | const char *buf, size_t size) | ||
302 | { | ||
303 | int r; | ||
304 | u8 alpha; | ||
305 | struct omap_overlay_info info; | ||
306 | |||
307 | if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0) | ||
308 | return -ENODEV; | ||
309 | |||
310 | r = kstrtou8(buf, 0, &alpha); | ||
311 | if (r) | ||
312 | return r; | ||
313 | |||
314 | ovl->get_overlay_info(ovl, &info); | ||
315 | |||
316 | info.pre_mult_alpha = alpha; | ||
317 | |||
318 | r = ovl->set_overlay_info(ovl, &info); | ||
319 | if (r) | ||
320 | return r; | ||
321 | |||
322 | if (ovl->manager) { | ||
323 | r = ovl->manager->apply(ovl->manager); | ||
324 | if (r) | ||
325 | return r; | ||
326 | } | ||
327 | |||
328 | return size; | ||
329 | } | ||
330 | |||
331 | static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf) | ||
332 | { | ||
333 | struct omap_overlay_info info; | ||
334 | |||
335 | ovl->get_overlay_info(ovl, &info); | ||
336 | |||
337 | return snprintf(buf, PAGE_SIZE, "%d\n", info.zorder); | ||
338 | } | ||
339 | |||
340 | static ssize_t overlay_zorder_store(struct omap_overlay *ovl, | ||
341 | const char *buf, size_t size) | ||
342 | { | ||
343 | int r; | ||
344 | u8 zorder; | ||
345 | struct omap_overlay_info info; | ||
346 | |||
347 | if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0) | ||
348 | return -ENODEV; | ||
349 | |||
350 | r = kstrtou8(buf, 0, &zorder); | ||
351 | if (r) | ||
352 | return r; | ||
353 | |||
354 | ovl->get_overlay_info(ovl, &info); | ||
355 | |||
356 | info.zorder = zorder; | ||
357 | |||
358 | r = ovl->set_overlay_info(ovl, &info); | ||
359 | if (r) | ||
360 | return r; | ||
361 | |||
362 | if (ovl->manager) { | ||
363 | r = ovl->manager->apply(ovl->manager); | ||
364 | if (r) | ||
365 | return r; | ||
366 | } | ||
367 | |||
368 | return size; | ||
369 | } | ||
370 | |||
371 | struct overlay_attribute { | ||
372 | struct attribute attr; | ||
373 | ssize_t (*show)(struct omap_overlay *, char *); | ||
374 | ssize_t (*store)(struct omap_overlay *, const char *, size_t); | ||
375 | }; | ||
376 | |||
377 | #define OVERLAY_ATTR(_name, _mode, _show, _store) \ | ||
378 | struct overlay_attribute overlay_attr_##_name = \ | ||
379 | __ATTR(_name, _mode, _show, _store) | ||
380 | |||
381 | static OVERLAY_ATTR(name, S_IRUGO, overlay_name_show, NULL); | ||
382 | static OVERLAY_ATTR(manager, S_IRUGO|S_IWUSR, | ||
383 | overlay_manager_show, overlay_manager_store); | ||
384 | static OVERLAY_ATTR(input_size, S_IRUGO, overlay_input_size_show, NULL); | ||
385 | static OVERLAY_ATTR(screen_width, S_IRUGO, overlay_screen_width_show, NULL); | ||
386 | static OVERLAY_ATTR(position, S_IRUGO|S_IWUSR, | ||
387 | overlay_position_show, overlay_position_store); | ||
388 | static OVERLAY_ATTR(output_size, S_IRUGO|S_IWUSR, | ||
389 | overlay_output_size_show, overlay_output_size_store); | ||
390 | static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR, | ||
391 | overlay_enabled_show, overlay_enabled_store); | ||
392 | static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR, | ||
393 | overlay_global_alpha_show, overlay_global_alpha_store); | ||
394 | static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR, | ||
395 | overlay_pre_mult_alpha_show, | ||
396 | overlay_pre_mult_alpha_store); | ||
397 | static OVERLAY_ATTR(zorder, S_IRUGO|S_IWUSR, | ||
398 | overlay_zorder_show, overlay_zorder_store); | ||
399 | |||
400 | static struct attribute *overlay_sysfs_attrs[] = { | ||
401 | &overlay_attr_name.attr, | ||
402 | &overlay_attr_manager.attr, | ||
403 | &overlay_attr_input_size.attr, | ||
404 | &overlay_attr_screen_width.attr, | ||
405 | &overlay_attr_position.attr, | ||
406 | &overlay_attr_output_size.attr, | ||
407 | &overlay_attr_enabled.attr, | ||
408 | &overlay_attr_global_alpha.attr, | ||
409 | &overlay_attr_pre_mult_alpha.attr, | ||
410 | &overlay_attr_zorder.attr, | ||
411 | NULL | ||
412 | }; | ||
413 | |||
414 | static ssize_t overlay_attr_show(struct kobject *kobj, struct attribute *attr, | ||
415 | char *buf) | ||
416 | { | ||
417 | struct omap_overlay *overlay; | ||
418 | struct overlay_attribute *overlay_attr; | ||
419 | |||
420 | overlay = container_of(kobj, struct omap_overlay, kobj); | ||
421 | overlay_attr = container_of(attr, struct overlay_attribute, attr); | ||
422 | |||
423 | if (!overlay_attr->show) | ||
424 | return -ENOENT; | ||
425 | |||
426 | return overlay_attr->show(overlay, buf); | ||
427 | } | ||
428 | |||
429 | static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr, | ||
430 | const char *buf, size_t size) | ||
431 | { | ||
432 | struct omap_overlay *overlay; | ||
433 | struct overlay_attribute *overlay_attr; | ||
434 | |||
435 | overlay = container_of(kobj, struct omap_overlay, kobj); | ||
436 | overlay_attr = container_of(attr, struct overlay_attribute, attr); | ||
437 | |||
438 | if (!overlay_attr->store) | ||
439 | return -ENOENT; | ||
440 | |||
441 | return overlay_attr->store(overlay, buf, size); | ||
442 | } | ||
443 | |||
444 | static const struct sysfs_ops overlay_sysfs_ops = { | ||
445 | .show = overlay_attr_show, | ||
446 | .store = overlay_attr_store, | ||
447 | }; | ||
448 | |||
449 | static struct kobj_type overlay_ktype = { | ||
450 | .sysfs_ops = &overlay_sysfs_ops, | ||
451 | .default_attrs = overlay_sysfs_attrs, | ||
452 | }; | ||
453 | |||
454 | int omap_dss_get_num_overlays(void) | 48 | int omap_dss_get_num_overlays(void) |
455 | { | 49 | { |
456 | return num_overlays; | 50 | return num_overlays; |
@@ -507,97 +101,25 @@ void dss_init_overlays(struct platform_device *pdev) | |||
507 | ovl->set_overlay_info = &dss_ovl_set_info; | 101 | ovl->set_overlay_info = &dss_ovl_set_info; |
508 | ovl->get_overlay_info = &dss_ovl_get_info; | 102 | ovl->get_overlay_info = &dss_ovl_get_info; |
509 | ovl->wait_for_go = &dss_mgr_wait_for_go_ovl; | 103 | ovl->wait_for_go = &dss_mgr_wait_for_go_ovl; |
104 | ovl->get_device = &dss_ovl_get_device; | ||
510 | 105 | ||
511 | ovl->caps = dss_feat_get_overlay_caps(ovl->id); | 106 | ovl->caps = dss_feat_get_overlay_caps(ovl->id); |
512 | ovl->supported_modes = | 107 | ovl->supported_modes = |
513 | dss_feat_get_supported_color_modes(ovl->id); | 108 | dss_feat_get_supported_color_modes(ovl->id); |
514 | 109 | ||
515 | r = kobject_init_and_add(&ovl->kobj, &overlay_ktype, | 110 | r = dss_overlay_kobj_init(ovl, pdev); |
516 | &pdev->dev.kobj, "overlay%d", i); | ||
517 | |||
518 | if (r) | 111 | if (r) |
519 | DSSERR("failed to create sysfs file\n"); | 112 | DSSERR("failed to create sysfs file\n"); |
520 | } | 113 | } |
521 | } | 114 | } |
522 | 115 | ||
523 | /* connect overlays to the new device, if not already connected. if force | ||
524 | * selected, connect always. */ | ||
525 | void dss_recheck_connections(struct omap_dss_device *dssdev, bool force) | ||
526 | { | ||
527 | int i; | ||
528 | struct omap_overlay_manager *lcd_mgr; | ||
529 | struct omap_overlay_manager *tv_mgr; | ||
530 | struct omap_overlay_manager *lcd2_mgr = NULL; | ||
531 | struct omap_overlay_manager *lcd3_mgr = NULL; | ||
532 | struct omap_overlay_manager *mgr = NULL; | ||
533 | |||
534 | lcd_mgr = omap_dss_get_overlay_manager(OMAP_DSS_CHANNEL_LCD); | ||
535 | tv_mgr = omap_dss_get_overlay_manager(OMAP_DSS_CHANNEL_DIGIT); | ||
536 | if (dss_has_feature(FEAT_MGR_LCD3)) | ||
537 | lcd3_mgr = omap_dss_get_overlay_manager(OMAP_DSS_CHANNEL_LCD3); | ||
538 | if (dss_has_feature(FEAT_MGR_LCD2)) | ||
539 | lcd2_mgr = omap_dss_get_overlay_manager(OMAP_DSS_CHANNEL_LCD2); | ||
540 | |||
541 | if (dssdev->channel == OMAP_DSS_CHANNEL_LCD3) { | ||
542 | if (!lcd3_mgr->device || force) { | ||
543 | if (lcd3_mgr->device) | ||
544 | lcd3_mgr->unset_device(lcd3_mgr); | ||
545 | lcd3_mgr->set_device(lcd3_mgr, dssdev); | ||
546 | mgr = lcd3_mgr; | ||
547 | } | ||
548 | } else if (dssdev->channel == OMAP_DSS_CHANNEL_LCD2) { | ||
549 | if (!lcd2_mgr->device || force) { | ||
550 | if (lcd2_mgr->device) | ||
551 | lcd2_mgr->unset_device(lcd2_mgr); | ||
552 | lcd2_mgr->set_device(lcd2_mgr, dssdev); | ||
553 | mgr = lcd2_mgr; | ||
554 | } | ||
555 | } else if (dssdev->type != OMAP_DISPLAY_TYPE_VENC | ||
556 | && dssdev->type != OMAP_DISPLAY_TYPE_HDMI) { | ||
557 | if (!lcd_mgr->device || force) { | ||
558 | if (lcd_mgr->device) | ||
559 | lcd_mgr->unset_device(lcd_mgr); | ||
560 | lcd_mgr->set_device(lcd_mgr, dssdev); | ||
561 | mgr = lcd_mgr; | ||
562 | } | ||
563 | } | ||
564 | |||
565 | if (dssdev->type == OMAP_DISPLAY_TYPE_VENC | ||
566 | || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) { | ||
567 | if (!tv_mgr->device || force) { | ||
568 | if (tv_mgr->device) | ||
569 | tv_mgr->unset_device(tv_mgr); | ||
570 | tv_mgr->set_device(tv_mgr, dssdev); | ||
571 | mgr = tv_mgr; | ||
572 | } | ||
573 | } | ||
574 | |||
575 | if (mgr) { | ||
576 | dispc_runtime_get(); | ||
577 | |||
578 | for (i = 0; i < dss_feat_get_num_ovls(); i++) { | ||
579 | struct omap_overlay *ovl; | ||
580 | ovl = omap_dss_get_overlay(i); | ||
581 | if (!ovl->manager || force) { | ||
582 | if (ovl->manager) | ||
583 | ovl->unset_manager(ovl); | ||
584 | ovl->set_manager(ovl, mgr); | ||
585 | } | ||
586 | } | ||
587 | |||
588 | dispc_runtime_put(); | ||
589 | } | ||
590 | } | ||
591 | |||
592 | void dss_uninit_overlays(struct platform_device *pdev) | 116 | void dss_uninit_overlays(struct platform_device *pdev) |
593 | { | 117 | { |
594 | int i; | 118 | int i; |
595 | 119 | ||
596 | for (i = 0; i < num_overlays; ++i) { | 120 | for (i = 0; i < num_overlays; ++i) { |
597 | struct omap_overlay *ovl = &overlays[i]; | 121 | struct omap_overlay *ovl = &overlays[i]; |
598 | 122 | dss_overlay_kobj_uninit(ovl); | |
599 | kobject_del(&ovl->kobj); | ||
600 | kobject_put(&ovl->kobj); | ||
601 | } | 123 | } |
602 | 124 | ||
603 | kfree(overlays); | 125 | kfree(overlays); |
diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index 7c087424b634..7282e5af3e1a 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c | |||
@@ -111,6 +111,13 @@ static struct { | |||
111 | struct omap_dss_device *dssdev[2]; | 111 | struct omap_dss_device *dssdev[2]; |
112 | 112 | ||
113 | struct semaphore bus_lock; | 113 | struct semaphore bus_lock; |
114 | |||
115 | struct omap_video_timings timings; | ||
116 | int pixel_size; | ||
117 | int data_lines; | ||
118 | struct rfbi_timings intf_timings; | ||
119 | |||
120 | struct omap_dss_output output; | ||
114 | } rfbi; | 121 | } rfbi; |
115 | 122 | ||
116 | static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val) | 123 | static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val) |
@@ -300,30 +307,23 @@ void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width, | |||
300 | } | 307 | } |
301 | EXPORT_SYMBOL(omap_rfbi_write_pixels); | 308 | EXPORT_SYMBOL(omap_rfbi_write_pixels); |
302 | 309 | ||
303 | static int rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width, | 310 | static int rfbi_transfer_area(struct omap_dss_device *dssdev, |
304 | u16 height, void (*callback)(void *data), void *data) | 311 | void (*callback)(void *data), void *data) |
305 | { | 312 | { |
306 | u32 l; | 313 | u32 l; |
307 | int r; | 314 | int r; |
308 | struct omap_video_timings timings = { | 315 | struct omap_overlay_manager *mgr = dssdev->output->manager; |
309 | .hsw = 1, | 316 | u16 width = rfbi.timings.x_res; |
310 | .hfp = 1, | 317 | u16 height = rfbi.timings.y_res; |
311 | .hbp = 1, | ||
312 | .vsw = 1, | ||
313 | .vfp = 0, | ||
314 | .vbp = 0, | ||
315 | .x_res = width, | ||
316 | .y_res = height, | ||
317 | }; | ||
318 | 318 | ||
319 | /*BUG_ON(callback == 0);*/ | 319 | /*BUG_ON(callback == 0);*/ |
320 | BUG_ON(rfbi.framedone_callback != NULL); | 320 | BUG_ON(rfbi.framedone_callback != NULL); |
321 | 321 | ||
322 | DSSDBG("rfbi_transfer_area %dx%d\n", width, height); | 322 | DSSDBG("rfbi_transfer_area %dx%d\n", width, height); |
323 | 323 | ||
324 | dss_mgr_set_timings(dssdev->manager, &timings); | 324 | dss_mgr_set_timings(mgr, &rfbi.timings); |
325 | 325 | ||
326 | r = dss_mgr_enable(dssdev->manager); | 326 | r = dss_mgr_enable(mgr); |
327 | if (r) | 327 | if (r) |
328 | return r; | 328 | return r; |
329 | 329 | ||
@@ -770,62 +770,45 @@ static int rfbi_configure(int rfbi_module, int bpp, int lines) | |||
770 | return 0; | 770 | return 0; |
771 | } | 771 | } |
772 | 772 | ||
773 | int omap_rfbi_configure(struct omap_dss_device *dssdev, int pixel_size, | 773 | int omap_rfbi_configure(struct omap_dss_device *dssdev) |
774 | int data_lines) | ||
775 | { | 774 | { |
776 | return rfbi_configure(dssdev->phy.rfbi.channel, pixel_size, data_lines); | 775 | return rfbi_configure(dssdev->phy.rfbi.channel, rfbi.pixel_size, |
776 | rfbi.data_lines); | ||
777 | } | 777 | } |
778 | EXPORT_SYMBOL(omap_rfbi_configure); | 778 | EXPORT_SYMBOL(omap_rfbi_configure); |
779 | 779 | ||
780 | int omap_rfbi_prepare_update(struct omap_dss_device *dssdev, | 780 | int omap_rfbi_update(struct omap_dss_device *dssdev, void (*callback)(void *), |
781 | u16 *x, u16 *y, u16 *w, u16 *h) | 781 | void *data) |
782 | { | 782 | { |
783 | u16 dw, dh; | 783 | return rfbi_transfer_area(dssdev, callback, data); |
784 | struct omap_video_timings timings = { | 784 | } |
785 | .hsw = 1, | 785 | EXPORT_SYMBOL(omap_rfbi_update); |
786 | .hfp = 1, | ||
787 | .hbp = 1, | ||
788 | .vsw = 1, | ||
789 | .vfp = 0, | ||
790 | .vbp = 0, | ||
791 | .x_res = *w, | ||
792 | .y_res = *h, | ||
793 | }; | ||
794 | |||
795 | dssdev->driver->get_resolution(dssdev, &dw, &dh); | ||
796 | |||
797 | if (*x > dw || *y > dh) | ||
798 | return -EINVAL; | ||
799 | |||
800 | if (*x + *w > dw) | ||
801 | return -EINVAL; | ||
802 | |||
803 | if (*y + *h > dh) | ||
804 | return -EINVAL; | ||
805 | |||
806 | if (*w == 1) | ||
807 | return -EINVAL; | ||
808 | |||
809 | if (*w == 0 || *h == 0) | ||
810 | return -EINVAL; | ||
811 | |||
812 | dss_mgr_set_timings(dssdev->manager, &timings); | ||
813 | 786 | ||
814 | return 0; | 787 | void omapdss_rfbi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h) |
788 | { | ||
789 | rfbi.timings.x_res = w; | ||
790 | rfbi.timings.y_res = h; | ||
815 | } | 791 | } |
816 | EXPORT_SYMBOL(omap_rfbi_prepare_update); | 792 | EXPORT_SYMBOL(omapdss_rfbi_set_size); |
817 | 793 | ||
818 | int omap_rfbi_update(struct omap_dss_device *dssdev, | 794 | void omapdss_rfbi_set_pixel_size(struct omap_dss_device *dssdev, int pixel_size) |
819 | u16 x, u16 y, u16 w, u16 h, | ||
820 | void (*callback)(void *), void *data) | ||
821 | { | 795 | { |
822 | int r; | 796 | rfbi.pixel_size = pixel_size; |
797 | } | ||
798 | EXPORT_SYMBOL(omapdss_rfbi_set_pixel_size); | ||
823 | 799 | ||
824 | r = rfbi_transfer_area(dssdev, w, h, callback, data); | 800 | void omapdss_rfbi_set_data_lines(struct omap_dss_device *dssdev, int data_lines) |
801 | { | ||
802 | rfbi.data_lines = data_lines; | ||
803 | } | ||
804 | EXPORT_SYMBOL(omapdss_rfbi_set_data_lines); | ||
825 | 805 | ||
826 | return r; | 806 | void omapdss_rfbi_set_interface_timings(struct omap_dss_device *dssdev, |
807 | struct rfbi_timings *timings) | ||
808 | { | ||
809 | rfbi.intf_timings = *timings; | ||
827 | } | 810 | } |
828 | EXPORT_SYMBOL(omap_rfbi_update); | 811 | EXPORT_SYMBOL(omapdss_rfbi_set_interface_timings); |
829 | 812 | ||
830 | static void rfbi_dump_regs(struct seq_file *s) | 813 | static void rfbi_dump_regs(struct seq_file *s) |
831 | { | 814 | { |
@@ -869,6 +852,7 @@ static void rfbi_dump_regs(struct seq_file *s) | |||
869 | 852 | ||
870 | static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev) | 853 | static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev) |
871 | { | 854 | { |
855 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
872 | struct dss_lcd_mgr_config mgr_config; | 856 | struct dss_lcd_mgr_config mgr_config; |
873 | 857 | ||
874 | mgr_config.io_pad_mode = DSS_IO_PAD_MODE_RFBI; | 858 | mgr_config.io_pad_mode = DSS_IO_PAD_MODE_RFBI; |
@@ -877,18 +861,40 @@ static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev) | |||
877 | /* Do we need fifohandcheck for RFBI? */ | 861 | /* Do we need fifohandcheck for RFBI? */ |
878 | mgr_config.fifohandcheck = false; | 862 | mgr_config.fifohandcheck = false; |
879 | 863 | ||
880 | mgr_config.video_port_width = dssdev->ctrl.pixel_size; | 864 | mgr_config.video_port_width = rfbi.pixel_size; |
881 | mgr_config.lcden_sig_polarity = 0; | 865 | mgr_config.lcden_sig_polarity = 0; |
882 | 866 | ||
883 | dss_mgr_set_lcd_config(dssdev->manager, &mgr_config); | 867 | dss_mgr_set_lcd_config(mgr, &mgr_config); |
868 | |||
869 | /* | ||
870 | * Set rfbi.timings with default values, the x_res and y_res fields | ||
871 | * are expected to be already configured by the panel driver via | ||
872 | * omapdss_rfbi_set_size() | ||
873 | */ | ||
874 | rfbi.timings.hsw = 1; | ||
875 | rfbi.timings.hfp = 1; | ||
876 | rfbi.timings.hbp = 1; | ||
877 | rfbi.timings.vsw = 1; | ||
878 | rfbi.timings.vfp = 0; | ||
879 | rfbi.timings.vbp = 0; | ||
880 | |||
881 | rfbi.timings.interlace = false; | ||
882 | rfbi.timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH; | ||
883 | rfbi.timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH; | ||
884 | rfbi.timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; | ||
885 | rfbi.timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH; | ||
886 | rfbi.timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; | ||
887 | |||
888 | dss_mgr_set_timings(mgr, &rfbi.timings); | ||
884 | } | 889 | } |
885 | 890 | ||
886 | int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev) | 891 | int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev) |
887 | { | 892 | { |
893 | struct omap_dss_output *out = dssdev->output; | ||
888 | int r; | 894 | int r; |
889 | 895 | ||
890 | if (dssdev->manager == NULL) { | 896 | if (out == NULL || out->manager == NULL) { |
891 | DSSERR("failed to enable display: no manager\n"); | 897 | DSSERR("failed to enable display: no output/manager\n"); |
892 | return -ENODEV; | 898 | return -ENODEV; |
893 | } | 899 | } |
894 | 900 | ||
@@ -911,13 +917,10 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev) | |||
911 | 917 | ||
912 | rfbi_config_lcd_manager(dssdev); | 918 | rfbi_config_lcd_manager(dssdev); |
913 | 919 | ||
914 | rfbi_configure(dssdev->phy.rfbi.channel, | 920 | rfbi_configure(dssdev->phy.rfbi.channel, rfbi.pixel_size, |
915 | dssdev->ctrl.pixel_size, | 921 | rfbi.data_lines); |
916 | dssdev->phy.rfbi.data_lines); | ||
917 | |||
918 | rfbi_set_timings(dssdev->phy.rfbi.channel, | ||
919 | &dssdev->ctrl.rfbi_timings); | ||
920 | 922 | ||
923 | rfbi_set_timings(dssdev->phy.rfbi.channel, &rfbi.intf_timings); | ||
921 | 924 | ||
922 | return 0; | 925 | return 0; |
923 | err1: | 926 | err1: |
@@ -941,14 +944,17 @@ EXPORT_SYMBOL(omapdss_rfbi_display_disable); | |||
941 | static int __init rfbi_init_display(struct omap_dss_device *dssdev) | 944 | static int __init rfbi_init_display(struct omap_dss_device *dssdev) |
942 | { | 945 | { |
943 | rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev; | 946 | rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev; |
944 | dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; | ||
945 | return 0; | 947 | return 0; |
946 | } | 948 | } |
947 | 949 | ||
948 | static void __init rfbi_probe_pdata(struct platform_device *pdev) | 950 | static struct omap_dss_device * __init rfbi_find_dssdev(struct platform_device *pdev) |
949 | { | 951 | { |
950 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | 952 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; |
951 | int i, r; | 953 | const char *def_disp_name = dss_get_default_display_name(); |
954 | struct omap_dss_device *def_dssdev; | ||
955 | int i; | ||
956 | |||
957 | def_dssdev = NULL; | ||
952 | 958 | ||
953 | for (i = 0; i < pdata->num_devices; ++i) { | 959 | for (i = 0; i < pdata->num_devices; ++i) { |
954 | struct omap_dss_device *dssdev = pdata->devices[i]; | 960 | struct omap_dss_device *dssdev = pdata->devices[i]; |
@@ -956,17 +962,67 @@ static void __init rfbi_probe_pdata(struct platform_device *pdev) | |||
956 | if (dssdev->type != OMAP_DISPLAY_TYPE_DBI) | 962 | if (dssdev->type != OMAP_DISPLAY_TYPE_DBI) |
957 | continue; | 963 | continue; |
958 | 964 | ||
959 | r = rfbi_init_display(dssdev); | 965 | if (def_dssdev == NULL) |
960 | if (r) { | 966 | def_dssdev = dssdev; |
961 | DSSERR("device %s init failed: %d\n", dssdev->name, r); | 967 | |
962 | continue; | 968 | if (def_disp_name != NULL && |
969 | strcmp(dssdev->name, def_disp_name) == 0) { | ||
970 | def_dssdev = dssdev; | ||
971 | break; | ||
963 | } | 972 | } |
973 | } | ||
974 | |||
975 | return def_dssdev; | ||
976 | } | ||
977 | |||
978 | static void __init rfbi_probe_pdata(struct platform_device *rfbidev) | ||
979 | { | ||
980 | struct omap_dss_device *plat_dssdev; | ||
981 | struct omap_dss_device *dssdev; | ||
982 | int r; | ||
983 | |||
984 | plat_dssdev = rfbi_find_dssdev(rfbidev); | ||
985 | |||
986 | if (!plat_dssdev) | ||
987 | return; | ||
988 | |||
989 | dssdev = dss_alloc_and_init_device(&rfbidev->dev); | ||
990 | if (!dssdev) | ||
991 | return; | ||
992 | |||
993 | dss_copy_device_pdata(dssdev, plat_dssdev); | ||
964 | 994 | ||
965 | r = omap_dss_register_device(dssdev, &pdev->dev, i); | 995 | r = rfbi_init_display(dssdev); |
966 | if (r) | 996 | if (r) { |
967 | DSSERR("device %s register failed: %d\n", | 997 | DSSERR("device %s init failed: %d\n", dssdev->name, r); |
968 | dssdev->name, r); | 998 | dss_put_device(dssdev); |
999 | return; | ||
969 | } | 1000 | } |
1001 | |||
1002 | r = dss_add_device(dssdev); | ||
1003 | if (r) { | ||
1004 | DSSERR("device %s register failed: %d\n", dssdev->name, r); | ||
1005 | dss_put_device(dssdev); | ||
1006 | return; | ||
1007 | } | ||
1008 | } | ||
1009 | |||
1010 | static void __init rfbi_init_output(struct platform_device *pdev) | ||
1011 | { | ||
1012 | struct omap_dss_output *out = &rfbi.output; | ||
1013 | |||
1014 | out->pdev = pdev; | ||
1015 | out->id = OMAP_DSS_OUTPUT_DBI; | ||
1016 | out->type = OMAP_DISPLAY_TYPE_DBI; | ||
1017 | |||
1018 | dss_register_output(out); | ||
1019 | } | ||
1020 | |||
1021 | static void __exit rfbi_uninit_output(struct platform_device *pdev) | ||
1022 | { | ||
1023 | struct omap_dss_output *out = &rfbi.output; | ||
1024 | |||
1025 | dss_unregister_output(out); | ||
970 | } | 1026 | } |
971 | 1027 | ||
972 | /* RFBI HW IP initialisation */ | 1028 | /* RFBI HW IP initialisation */ |
@@ -1020,6 +1076,8 @@ static int __init omap_rfbihw_probe(struct platform_device *pdev) | |||
1020 | 1076 | ||
1021 | dss_debugfs_create_file("rfbi", rfbi_dump_regs); | 1077 | dss_debugfs_create_file("rfbi", rfbi_dump_regs); |
1022 | 1078 | ||
1079 | rfbi_init_output(pdev); | ||
1080 | |||
1023 | rfbi_probe_pdata(pdev); | 1081 | rfbi_probe_pdata(pdev); |
1024 | 1082 | ||
1025 | return 0; | 1083 | return 0; |
@@ -1031,8 +1089,12 @@ err_runtime_get: | |||
1031 | 1089 | ||
1032 | static int __exit omap_rfbihw_remove(struct platform_device *pdev) | 1090 | static int __exit omap_rfbihw_remove(struct platform_device *pdev) |
1033 | { | 1091 | { |
1034 | omap_dss_unregister_child_devices(&pdev->dev); | 1092 | dss_unregister_child_devices(&pdev->dev); |
1093 | |||
1094 | rfbi_uninit_output(pdev); | ||
1095 | |||
1035 | pm_runtime_disable(&pdev->dev); | 1096 | pm_runtime_disable(&pdev->dev); |
1097 | |||
1036 | return 0; | 1098 | return 0; |
1037 | } | 1099 | } |
1038 | 1100 | ||
diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index f43bfe17b3b6..7760851f6e5d 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/regulator/consumer.h> | 25 | #include <linux/regulator/consumer.h> |
26 | #include <linux/export.h> | 26 | #include <linux/export.h> |
27 | #include <linux/platform_device.h> | 27 | #include <linux/platform_device.h> |
28 | #include <linux/string.h> | ||
28 | 29 | ||
29 | #include <video/omapdss.h> | 30 | #include <video/omapdss.h> |
30 | #include "dss.h" | 31 | #include "dss.h" |
@@ -34,10 +35,16 @@ static struct { | |||
34 | struct regulator *vdds_sdi_reg; | 35 | struct regulator *vdds_sdi_reg; |
35 | 36 | ||
36 | struct dss_lcd_mgr_config mgr_config; | 37 | struct dss_lcd_mgr_config mgr_config; |
38 | struct omap_video_timings timings; | ||
39 | int datapairs; | ||
40 | |||
41 | struct omap_dss_output output; | ||
37 | } sdi; | 42 | } sdi; |
38 | 43 | ||
39 | static void sdi_config_lcd_manager(struct omap_dss_device *dssdev) | 44 | static void sdi_config_lcd_manager(struct omap_dss_device *dssdev) |
40 | { | 45 | { |
46 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
47 | |||
41 | sdi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; | 48 | sdi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; |
42 | 49 | ||
43 | sdi.mgr_config.stallmode = false; | 50 | sdi.mgr_config.stallmode = false; |
@@ -46,19 +53,20 @@ static void sdi_config_lcd_manager(struct omap_dss_device *dssdev) | |||
46 | sdi.mgr_config.video_port_width = 24; | 53 | sdi.mgr_config.video_port_width = 24; |
47 | sdi.mgr_config.lcden_sig_polarity = 1; | 54 | sdi.mgr_config.lcden_sig_polarity = 1; |
48 | 55 | ||
49 | dss_mgr_set_lcd_config(dssdev->manager, &sdi.mgr_config); | 56 | dss_mgr_set_lcd_config(mgr, &sdi.mgr_config); |
50 | } | 57 | } |
51 | 58 | ||
52 | int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) | 59 | int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) |
53 | { | 60 | { |
54 | struct omap_video_timings *t = &dssdev->panel.timings; | 61 | struct omap_dss_output *out = dssdev->output; |
62 | struct omap_video_timings *t = &sdi.timings; | ||
55 | struct dss_clock_info dss_cinfo; | 63 | struct dss_clock_info dss_cinfo; |
56 | struct dispc_clock_info dispc_cinfo; | 64 | struct dispc_clock_info dispc_cinfo; |
57 | unsigned long pck; | 65 | unsigned long pck; |
58 | int r; | 66 | int r; |
59 | 67 | ||
60 | if (dssdev->manager == NULL) { | 68 | if (out == NULL || out->manager == NULL) { |
61 | DSSERR("failed to enable display: no manager\n"); | 69 | DSSERR("failed to enable display: no output/manager\n"); |
62 | return -ENODEV; | 70 | return -ENODEV; |
63 | } | 71 | } |
64 | 72 | ||
@@ -77,8 +85,8 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) | |||
77 | goto err_get_dispc; | 85 | goto err_get_dispc; |
78 | 86 | ||
79 | /* 15.5.9.1.2 */ | 87 | /* 15.5.9.1.2 */ |
80 | dssdev->panel.timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; | 88 | t->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; |
81 | dssdev->panel.timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; | 89 | t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; |
82 | 90 | ||
83 | r = dss_calc_clock_div(t->pixel_clock * 1000, &dss_cinfo, &dispc_cinfo); | 91 | r = dss_calc_clock_div(t->pixel_clock * 1000, &dss_cinfo, &dispc_cinfo); |
84 | if (r) | 92 | if (r) |
@@ -97,7 +105,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) | |||
97 | } | 105 | } |
98 | 106 | ||
99 | 107 | ||
100 | dss_mgr_set_timings(dssdev->manager, t); | 108 | dss_mgr_set_timings(out->manager, t); |
101 | 109 | ||
102 | r = dss_set_clock_div(&dss_cinfo); | 110 | r = dss_set_clock_div(&dss_cinfo); |
103 | if (r) | 111 | if (r) |
@@ -116,16 +124,15 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) | |||
116 | * need to care about the shadow register mechanism for pck-free. The | 124 | * need to care about the shadow register mechanism for pck-free. The |
117 | * exact reason for this is unknown. | 125 | * exact reason for this is unknown. |
118 | */ | 126 | */ |
119 | dispc_mgr_set_clock_div(dssdev->manager->id, | 127 | dispc_mgr_set_clock_div(out->manager->id, &sdi.mgr_config.clock_info); |
120 | &sdi.mgr_config.clock_info); | ||
121 | 128 | ||
122 | dss_sdi_init(dssdev->phy.sdi.datapairs); | 129 | dss_sdi_init(sdi.datapairs); |
123 | r = dss_sdi_enable(); | 130 | r = dss_sdi_enable(); |
124 | if (r) | 131 | if (r) |
125 | goto err_sdi_enable; | 132 | goto err_sdi_enable; |
126 | mdelay(2); | 133 | mdelay(2); |
127 | 134 | ||
128 | r = dss_mgr_enable(dssdev->manager); | 135 | r = dss_mgr_enable(out->manager); |
129 | if (r) | 136 | if (r) |
130 | goto err_mgr_enable; | 137 | goto err_mgr_enable; |
131 | 138 | ||
@@ -148,7 +155,9 @@ EXPORT_SYMBOL(omapdss_sdi_display_enable); | |||
148 | 155 | ||
149 | void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) | 156 | void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) |
150 | { | 157 | { |
151 | dss_mgr_disable(dssdev->manager); | 158 | struct omap_overlay_manager *mgr = dssdev->output->manager; |
159 | |||
160 | dss_mgr_disable(mgr); | ||
152 | 161 | ||
153 | dss_sdi_disable(); | 162 | dss_sdi_disable(); |
154 | 163 | ||
@@ -160,6 +169,19 @@ void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) | |||
160 | } | 169 | } |
161 | EXPORT_SYMBOL(omapdss_sdi_display_disable); | 170 | EXPORT_SYMBOL(omapdss_sdi_display_disable); |
162 | 171 | ||
172 | void omapdss_sdi_set_timings(struct omap_dss_device *dssdev, | ||
173 | struct omap_video_timings *timings) | ||
174 | { | ||
175 | sdi.timings = *timings; | ||
176 | } | ||
177 | EXPORT_SYMBOL(omapdss_sdi_set_timings); | ||
178 | |||
179 | void omapdss_sdi_set_datapairs(struct omap_dss_device *dssdev, int datapairs) | ||
180 | { | ||
181 | sdi.datapairs = datapairs; | ||
182 | } | ||
183 | EXPORT_SYMBOL(omapdss_sdi_set_datapairs); | ||
184 | |||
163 | static int __init sdi_init_display(struct omap_dss_device *dssdev) | 185 | static int __init sdi_init_display(struct omap_dss_device *dssdev) |
164 | { | 186 | { |
165 | DSSDBG("SDI init\n"); | 187 | DSSDBG("SDI init\n"); |
@@ -180,10 +202,14 @@ static int __init sdi_init_display(struct omap_dss_device *dssdev) | |||
180 | return 0; | 202 | return 0; |
181 | } | 203 | } |
182 | 204 | ||
183 | static void __init sdi_probe_pdata(struct platform_device *pdev) | 205 | static struct omap_dss_device * __init sdi_find_dssdev(struct platform_device *pdev) |
184 | { | 206 | { |
185 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | 207 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; |
186 | int i, r; | 208 | const char *def_disp_name = dss_get_default_display_name(); |
209 | struct omap_dss_device *def_dssdev; | ||
210 | int i; | ||
211 | |||
212 | def_dssdev = NULL; | ||
187 | 213 | ||
188 | for (i = 0; i < pdata->num_devices; ++i) { | 214 | for (i = 0; i < pdata->num_devices; ++i) { |
189 | struct omap_dss_device *dssdev = pdata->devices[i]; | 215 | struct omap_dss_device *dssdev = pdata->devices[i]; |
@@ -191,21 +217,73 @@ static void __init sdi_probe_pdata(struct platform_device *pdev) | |||
191 | if (dssdev->type != OMAP_DISPLAY_TYPE_SDI) | 217 | if (dssdev->type != OMAP_DISPLAY_TYPE_SDI) |
192 | continue; | 218 | continue; |
193 | 219 | ||
194 | r = sdi_init_display(dssdev); | 220 | if (def_dssdev == NULL) |
195 | if (r) { | 221 | def_dssdev = dssdev; |
196 | DSSERR("device %s init failed: %d\n", dssdev->name, r); | 222 | |
197 | continue; | 223 | if (def_disp_name != NULL && |
224 | strcmp(dssdev->name, def_disp_name) == 0) { | ||
225 | def_dssdev = dssdev; | ||
226 | break; | ||
198 | } | 227 | } |
228 | } | ||
229 | |||
230 | return def_dssdev; | ||
231 | } | ||
232 | |||
233 | static void __init sdi_probe_pdata(struct platform_device *sdidev) | ||
234 | { | ||
235 | struct omap_dss_device *plat_dssdev; | ||
236 | struct omap_dss_device *dssdev; | ||
237 | int r; | ||
238 | |||
239 | plat_dssdev = sdi_find_dssdev(sdidev); | ||
199 | 240 | ||
200 | r = omap_dss_register_device(dssdev, &pdev->dev, i); | 241 | if (!plat_dssdev) |
201 | if (r) | 242 | return; |
202 | DSSERR("device %s register failed: %d\n", | 243 | |
203 | dssdev->name, r); | 244 | dssdev = dss_alloc_and_init_device(&sdidev->dev); |
245 | if (!dssdev) | ||
246 | return; | ||
247 | |||
248 | dss_copy_device_pdata(dssdev, plat_dssdev); | ||
249 | |||
250 | r = sdi_init_display(dssdev); | ||
251 | if (r) { | ||
252 | DSSERR("device %s init failed: %d\n", dssdev->name, r); | ||
253 | dss_put_device(dssdev); | ||
254 | return; | ||
204 | } | 255 | } |
256 | |||
257 | r = dss_add_device(dssdev); | ||
258 | if (r) { | ||
259 | DSSERR("device %s register failed: %d\n", dssdev->name, r); | ||
260 | dss_put_device(dssdev); | ||
261 | return; | ||
262 | } | ||
263 | } | ||
264 | |||
265 | static void __init sdi_init_output(struct platform_device *pdev) | ||
266 | { | ||
267 | struct omap_dss_output *out = &sdi.output; | ||
268 | |||
269 | out->pdev = pdev; | ||
270 | out->id = OMAP_DSS_OUTPUT_SDI; | ||
271 | out->type = OMAP_DISPLAY_TYPE_SDI; | ||
272 | |||
273 | dss_register_output(out); | ||
274 | } | ||
275 | |||
276 | static void __exit sdi_uninit_output(struct platform_device *pdev) | ||
277 | { | ||
278 | struct omap_dss_output *out = &sdi.output; | ||
279 | |||
280 | dss_unregister_output(out); | ||
205 | } | 281 | } |
206 | 282 | ||
207 | static int __init omap_sdi_probe(struct platform_device *pdev) | 283 | static int __init omap_sdi_probe(struct platform_device *pdev) |
208 | { | 284 | { |
285 | sdi_init_output(pdev); | ||
286 | |||
209 | sdi_probe_pdata(pdev); | 287 | sdi_probe_pdata(pdev); |
210 | 288 | ||
211 | return 0; | 289 | return 0; |
@@ -213,7 +291,9 @@ static int __init omap_sdi_probe(struct platform_device *pdev) | |||
213 | 291 | ||
214 | static int __exit omap_sdi_remove(struct platform_device *pdev) | 292 | static int __exit omap_sdi_remove(struct platform_device *pdev) |
215 | { | 293 | { |
216 | omap_dss_unregister_child_devices(&pdev->dev); | 294 | dss_unregister_child_devices(&pdev->dev); |
295 | |||
296 | sdi_uninit_output(pdev); | ||
217 | 297 | ||
218 | return 0; | 298 | return 0; |
219 | } | 299 | } |
diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index 3a220877461a..56efa3bb465d 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c | |||
@@ -36,7 +36,6 @@ | |||
36 | #include <linux/pm_runtime.h> | 36 | #include <linux/pm_runtime.h> |
37 | 37 | ||
38 | #include <video/omapdss.h> | 38 | #include <video/omapdss.h> |
39 | #include <plat/cpu.h> | ||
40 | 39 | ||
41 | #include "dss.h" | 40 | #include "dss.h" |
42 | #include "dss_features.h" | 41 | #include "dss_features.h" |
@@ -300,6 +299,12 @@ static struct { | |||
300 | struct regulator *vdda_dac_reg; | 299 | struct regulator *vdda_dac_reg; |
301 | 300 | ||
302 | struct clk *tv_dac_clk; | 301 | struct clk *tv_dac_clk; |
302 | |||
303 | struct omap_video_timings timings; | ||
304 | enum omap_dss_venc_type type; | ||
305 | bool invert_polarity; | ||
306 | |||
307 | struct omap_dss_output output; | ||
303 | } venc; | 308 | } venc; |
304 | 309 | ||
305 | static inline void venc_write_reg(int idx, u32 val) | 310 | static inline void venc_write_reg(int idx, u32 val) |
@@ -424,65 +429,67 @@ static const struct venc_config *venc_timings_to_config( | |||
424 | 429 | ||
425 | static int venc_power_on(struct omap_dss_device *dssdev) | 430 | static int venc_power_on(struct omap_dss_device *dssdev) |
426 | { | 431 | { |
432 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
427 | u32 l; | 433 | u32 l; |
428 | int r; | 434 | int r; |
429 | 435 | ||
436 | r = venc_runtime_get(); | ||
437 | if (r) | ||
438 | goto err0; | ||
439 | |||
430 | venc_reset(); | 440 | venc_reset(); |
431 | venc_write_config(venc_timings_to_config(&dssdev->panel.timings)); | 441 | venc_write_config(venc_timings_to_config(&venc.timings)); |
432 | 442 | ||
433 | dss_set_venc_output(dssdev->phy.venc.type); | 443 | dss_set_venc_output(venc.type); |
434 | dss_set_dac_pwrdn_bgz(1); | 444 | dss_set_dac_pwrdn_bgz(1); |
435 | 445 | ||
436 | l = 0; | 446 | l = 0; |
437 | 447 | ||
438 | if (dssdev->phy.venc.type == OMAP_DSS_VENC_TYPE_COMPOSITE) | 448 | if (venc.type == OMAP_DSS_VENC_TYPE_COMPOSITE) |
439 | l |= 1 << 1; | 449 | l |= 1 << 1; |
440 | else /* S-Video */ | 450 | else /* S-Video */ |
441 | l |= (1 << 0) | (1 << 2); | 451 | l |= (1 << 0) | (1 << 2); |
442 | 452 | ||
443 | if (dssdev->phy.venc.invert_polarity == false) | 453 | if (venc.invert_polarity == false) |
444 | l |= 1 << 3; | 454 | l |= 1 << 3; |
445 | 455 | ||
446 | venc_write_reg(VENC_OUTPUT_CONTROL, l); | 456 | venc_write_reg(VENC_OUTPUT_CONTROL, l); |
447 | 457 | ||
448 | dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings); | 458 | dss_mgr_set_timings(mgr, &venc.timings); |
449 | 459 | ||
450 | r = regulator_enable(venc.vdda_dac_reg); | 460 | r = regulator_enable(venc.vdda_dac_reg); |
451 | if (r) | 461 | if (r) |
452 | goto err; | 462 | goto err1; |
453 | |||
454 | if (dssdev->platform_enable) | ||
455 | dssdev->platform_enable(dssdev); | ||
456 | 463 | ||
457 | r = dss_mgr_enable(dssdev->manager); | 464 | r = dss_mgr_enable(mgr); |
458 | if (r) | 465 | if (r) |
459 | goto err; | 466 | goto err2; |
460 | 467 | ||
461 | return 0; | 468 | return 0; |
462 | 469 | ||
463 | err: | 470 | err2: |
471 | regulator_disable(venc.vdda_dac_reg); | ||
472 | err1: | ||
464 | venc_write_reg(VENC_OUTPUT_CONTROL, 0); | 473 | venc_write_reg(VENC_OUTPUT_CONTROL, 0); |
465 | dss_set_dac_pwrdn_bgz(0); | 474 | dss_set_dac_pwrdn_bgz(0); |
466 | 475 | ||
467 | if (dssdev->platform_disable) | 476 | venc_runtime_put(); |
468 | dssdev->platform_disable(dssdev); | 477 | err0: |
469 | |||
470 | regulator_disable(venc.vdda_dac_reg); | ||
471 | |||
472 | return r; | 478 | return r; |
473 | } | 479 | } |
474 | 480 | ||
475 | static void venc_power_off(struct omap_dss_device *dssdev) | 481 | static void venc_power_off(struct omap_dss_device *dssdev) |
476 | { | 482 | { |
483 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
484 | |||
477 | venc_write_reg(VENC_OUTPUT_CONTROL, 0); | 485 | venc_write_reg(VENC_OUTPUT_CONTROL, 0); |
478 | dss_set_dac_pwrdn_bgz(0); | 486 | dss_set_dac_pwrdn_bgz(0); |
479 | 487 | ||
480 | dss_mgr_disable(dssdev->manager); | 488 | dss_mgr_disable(mgr); |
481 | |||
482 | if (dssdev->platform_disable) | ||
483 | dssdev->platform_disable(dssdev); | ||
484 | 489 | ||
485 | regulator_disable(venc.vdda_dac_reg); | 490 | regulator_disable(venc.vdda_dac_reg); |
491 | |||
492 | venc_runtime_put(); | ||
486 | } | 493 | } |
487 | 494 | ||
488 | unsigned long venc_get_pixel_clock(void) | 495 | unsigned long venc_get_pixel_clock(void) |
@@ -491,171 +498,83 @@ unsigned long venc_get_pixel_clock(void) | |||
491 | return 13500000; | 498 | return 13500000; |
492 | } | 499 | } |
493 | 500 | ||
494 | static ssize_t display_output_type_show(struct device *dev, | 501 | int omapdss_venc_display_enable(struct omap_dss_device *dssdev) |
495 | struct device_attribute *attr, char *buf) | ||
496 | { | 502 | { |
497 | struct omap_dss_device *dssdev = to_dss_device(dev); | 503 | struct omap_dss_output *out = dssdev->output; |
498 | const char *ret; | 504 | int r; |
499 | |||
500 | switch (dssdev->phy.venc.type) { | ||
501 | case OMAP_DSS_VENC_TYPE_COMPOSITE: | ||
502 | ret = "composite"; | ||
503 | break; | ||
504 | case OMAP_DSS_VENC_TYPE_SVIDEO: | ||
505 | ret = "svideo"; | ||
506 | break; | ||
507 | default: | ||
508 | return -EINVAL; | ||
509 | } | ||
510 | |||
511 | return snprintf(buf, PAGE_SIZE, "%s\n", ret); | ||
512 | } | ||
513 | 505 | ||
514 | static ssize_t display_output_type_store(struct device *dev, | 506 | DSSDBG("venc_display_enable\n"); |
515 | struct device_attribute *attr, const char *buf, size_t size) | ||
516 | { | ||
517 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
518 | enum omap_dss_venc_type new_type; | ||
519 | |||
520 | if (sysfs_streq("composite", buf)) | ||
521 | new_type = OMAP_DSS_VENC_TYPE_COMPOSITE; | ||
522 | else if (sysfs_streq("svideo", buf)) | ||
523 | new_type = OMAP_DSS_VENC_TYPE_SVIDEO; | ||
524 | else | ||
525 | return -EINVAL; | ||
526 | 507 | ||
527 | mutex_lock(&venc.venc_lock); | 508 | mutex_lock(&venc.venc_lock); |
528 | 509 | ||
529 | if (dssdev->phy.venc.type != new_type) { | 510 | if (out == NULL || out->manager == NULL) { |
530 | dssdev->phy.venc.type = new_type; | 511 | DSSERR("Failed to enable display: no output/manager\n"); |
531 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { | 512 | r = -ENODEV; |
532 | venc_power_off(dssdev); | 513 | goto err0; |
533 | venc_power_on(dssdev); | ||
534 | } | ||
535 | } | 514 | } |
536 | 515 | ||
537 | mutex_unlock(&venc.venc_lock); | ||
538 | |||
539 | return size; | ||
540 | } | ||
541 | |||
542 | static DEVICE_ATTR(output_type, S_IRUGO | S_IWUSR, | ||
543 | display_output_type_show, display_output_type_store); | ||
544 | |||
545 | /* driver */ | ||
546 | static int venc_panel_probe(struct omap_dss_device *dssdev) | ||
547 | { | ||
548 | dssdev->panel.timings = omap_dss_pal_timings; | ||
549 | |||
550 | return device_create_file(&dssdev->dev, &dev_attr_output_type); | ||
551 | } | ||
552 | |||
553 | static void venc_panel_remove(struct omap_dss_device *dssdev) | ||
554 | { | ||
555 | device_remove_file(&dssdev->dev, &dev_attr_output_type); | ||
556 | } | ||
557 | |||
558 | static int venc_panel_enable(struct omap_dss_device *dssdev) | ||
559 | { | ||
560 | int r = 0; | ||
561 | |||
562 | DSSDBG("venc_enable_display\n"); | ||
563 | |||
564 | mutex_lock(&venc.venc_lock); | ||
565 | |||
566 | r = omap_dss_start_device(dssdev); | 516 | r = omap_dss_start_device(dssdev); |
567 | if (r) { | 517 | if (r) { |
568 | DSSERR("failed to start device\n"); | 518 | DSSERR("failed to start device\n"); |
569 | goto err0; | 519 | goto err0; |
570 | } | 520 | } |
571 | 521 | ||
572 | if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) { | 522 | if (dssdev->platform_enable) |
573 | r = -EINVAL; | 523 | dssdev->platform_enable(dssdev); |
574 | goto err1; | ||
575 | } | ||
576 | 524 | ||
577 | r = venc_runtime_get(); | ||
578 | if (r) | ||
579 | goto err1; | ||
580 | 525 | ||
581 | r = venc_power_on(dssdev); | 526 | r = venc_power_on(dssdev); |
582 | if (r) | 527 | if (r) |
583 | goto err2; | 528 | goto err1; |
584 | 529 | ||
585 | venc.wss_data = 0; | 530 | venc.wss_data = 0; |
586 | 531 | ||
587 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
588 | |||
589 | mutex_unlock(&venc.venc_lock); | 532 | mutex_unlock(&venc.venc_lock); |
533 | |||
590 | return 0; | 534 | return 0; |
591 | err2: | ||
592 | venc_runtime_put(); | ||
593 | err1: | 535 | err1: |
536 | if (dssdev->platform_disable) | ||
537 | dssdev->platform_disable(dssdev); | ||
594 | omap_dss_stop_device(dssdev); | 538 | omap_dss_stop_device(dssdev); |
595 | err0: | 539 | err0: |
596 | mutex_unlock(&venc.venc_lock); | 540 | mutex_unlock(&venc.venc_lock); |
597 | |||
598 | return r; | 541 | return r; |
599 | } | 542 | } |
600 | 543 | ||
601 | static void venc_panel_disable(struct omap_dss_device *dssdev) | 544 | void omapdss_venc_display_disable(struct omap_dss_device *dssdev) |
602 | { | 545 | { |
603 | DSSDBG("venc_disable_display\n"); | 546 | DSSDBG("venc_display_disable\n"); |
604 | 547 | ||
605 | mutex_lock(&venc.venc_lock); | 548 | mutex_lock(&venc.venc_lock); |
606 | 549 | ||
607 | if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED) | ||
608 | goto end; | ||
609 | |||
610 | if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) { | ||
611 | /* suspended is the same as disabled with venc */ | ||
612 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
613 | goto end; | ||
614 | } | ||
615 | |||
616 | venc_power_off(dssdev); | 550 | venc_power_off(dssdev); |
617 | 551 | ||
618 | venc_runtime_put(); | ||
619 | |||
620 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
621 | |||
622 | omap_dss_stop_device(dssdev); | 552 | omap_dss_stop_device(dssdev); |
623 | end: | ||
624 | mutex_unlock(&venc.venc_lock); | ||
625 | } | ||
626 | 553 | ||
627 | static int venc_panel_suspend(struct omap_dss_device *dssdev) | 554 | if (dssdev->platform_disable) |
628 | { | 555 | dssdev->platform_disable(dssdev); |
629 | venc_panel_disable(dssdev); | ||
630 | return 0; | ||
631 | } | ||
632 | 556 | ||
633 | static int venc_panel_resume(struct omap_dss_device *dssdev) | 557 | mutex_unlock(&venc.venc_lock); |
634 | { | ||
635 | return venc_panel_enable(dssdev); | ||
636 | } | 558 | } |
637 | 559 | ||
638 | static void venc_set_timings(struct omap_dss_device *dssdev, | 560 | void omapdss_venc_set_timings(struct omap_dss_device *dssdev, |
639 | struct omap_video_timings *timings) | 561 | struct omap_video_timings *timings) |
640 | { | 562 | { |
641 | DSSDBG("venc_set_timings\n"); | 563 | DSSDBG("venc_set_timings\n"); |
642 | 564 | ||
565 | mutex_lock(&venc.venc_lock); | ||
566 | |||
643 | /* Reset WSS data when the TV standard changes. */ | 567 | /* Reset WSS data when the TV standard changes. */ |
644 | if (memcmp(&dssdev->panel.timings, timings, sizeof(*timings))) | 568 | if (memcmp(&venc.timings, timings, sizeof(*timings))) |
645 | venc.wss_data = 0; | 569 | venc.wss_data = 0; |
646 | 570 | ||
647 | dssdev->panel.timings = *timings; | 571 | venc.timings = *timings; |
648 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { | 572 | |
649 | /* turn the venc off and on to get new timings to use */ | 573 | mutex_unlock(&venc.venc_lock); |
650 | venc_panel_disable(dssdev); | ||
651 | venc_panel_enable(dssdev); | ||
652 | } else { | ||
653 | dss_mgr_set_timings(dssdev->manager, timings); | ||
654 | } | ||
655 | } | 574 | } |
656 | 575 | ||
657 | static int venc_check_timings(struct omap_dss_device *dssdev, | 576 | int omapdss_venc_check_timings(struct omap_dss_device *dssdev, |
658 | struct omap_video_timings *timings) | 577 | struct omap_video_timings *timings) |
659 | { | 578 | { |
660 | DSSDBG("venc_check_timings\n"); | 579 | DSSDBG("venc_check_timings\n"); |
661 | 580 | ||
@@ -668,13 +587,13 @@ static int venc_check_timings(struct omap_dss_device *dssdev, | |||
668 | return -EINVAL; | 587 | return -EINVAL; |
669 | } | 588 | } |
670 | 589 | ||
671 | static u32 venc_get_wss(struct omap_dss_device *dssdev) | 590 | u32 omapdss_venc_get_wss(struct omap_dss_device *dssdev) |
672 | { | 591 | { |
673 | /* Invert due to VENC_L21_WC_CTL:INV=1 */ | 592 | /* Invert due to VENC_L21_WC_CTL:INV=1 */ |
674 | return (venc.wss_data >> 8) ^ 0xfffff; | 593 | return (venc.wss_data >> 8) ^ 0xfffff; |
675 | } | 594 | } |
676 | 595 | ||
677 | static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss) | 596 | int omapdss_venc_set_wss(struct omap_dss_device *dssdev, u32 wss) |
678 | { | 597 | { |
679 | const struct venc_config *config; | 598 | const struct venc_config *config; |
680 | int r; | 599 | int r; |
@@ -683,7 +602,7 @@ static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss) | |||
683 | 602 | ||
684 | mutex_lock(&venc.venc_lock); | 603 | mutex_lock(&venc.venc_lock); |
685 | 604 | ||
686 | config = venc_timings_to_config(&dssdev->panel.timings); | 605 | config = venc_timings_to_config(&venc.timings); |
687 | 606 | ||
688 | /* Invert due to VENC_L21_WC_CTL:INV=1 */ | 607 | /* Invert due to VENC_L21_WC_CTL:INV=1 */ |
689 | venc.wss_data = (wss ^ 0xfffff) << 8; | 608 | venc.wss_data = (wss ^ 0xfffff) << 8; |
@@ -703,30 +622,25 @@ err: | |||
703 | return r; | 622 | return r; |
704 | } | 623 | } |
705 | 624 | ||
706 | static struct omap_dss_driver venc_driver = { | 625 | void omapdss_venc_set_type(struct omap_dss_device *dssdev, |
707 | .probe = venc_panel_probe, | 626 | enum omap_dss_venc_type type) |
708 | .remove = venc_panel_remove, | 627 | { |
628 | mutex_lock(&venc.venc_lock); | ||
709 | 629 | ||
710 | .enable = venc_panel_enable, | 630 | venc.type = type; |
711 | .disable = venc_panel_disable, | ||
712 | .suspend = venc_panel_suspend, | ||
713 | .resume = venc_panel_resume, | ||
714 | 631 | ||
715 | .get_resolution = omapdss_default_get_resolution, | 632 | mutex_unlock(&venc.venc_lock); |
716 | .get_recommended_bpp = omapdss_default_get_recommended_bpp, | 633 | } |
717 | 634 | ||
718 | .set_timings = venc_set_timings, | 635 | void omapdss_venc_invert_vid_out_polarity(struct omap_dss_device *dssdev, |
719 | .check_timings = venc_check_timings, | 636 | bool invert_polarity) |
637 | { | ||
638 | mutex_lock(&venc.venc_lock); | ||
720 | 639 | ||
721 | .get_wss = venc_get_wss, | 640 | venc.invert_polarity = invert_polarity; |
722 | .set_wss = venc_set_wss, | ||
723 | 641 | ||
724 | .driver = { | 642 | mutex_unlock(&venc.venc_lock); |
725 | .name = "venc", | 643 | } |
726 | .owner = THIS_MODULE, | ||
727 | }, | ||
728 | }; | ||
729 | /* driver end */ | ||
730 | 644 | ||
731 | static int __init venc_init_display(struct omap_dss_device *dssdev) | 645 | static int __init venc_init_display(struct omap_dss_device *dssdev) |
732 | { | 646 | { |
@@ -752,11 +666,6 @@ static void venc_dump_regs(struct seq_file *s) | |||
752 | { | 666 | { |
753 | #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r)) | 667 | #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r)) |
754 | 668 | ||
755 | if (cpu_is_omap44xx()) { | ||
756 | seq_printf(s, "VENC currently disabled on OMAP44xx\n"); | ||
757 | return; | ||
758 | } | ||
759 | |||
760 | if (venc_runtime_get()) | 669 | if (venc_runtime_get()) |
761 | return; | 670 | return; |
762 | 671 | ||
@@ -832,10 +741,14 @@ static void venc_put_clocks(void) | |||
832 | clk_put(venc.tv_dac_clk); | 741 | clk_put(venc.tv_dac_clk); |
833 | } | 742 | } |
834 | 743 | ||
835 | static void __init venc_probe_pdata(struct platform_device *pdev) | 744 | static struct omap_dss_device * __init venc_find_dssdev(struct platform_device *pdev) |
836 | { | 745 | { |
837 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | 746 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; |
838 | int r, i; | 747 | const char *def_disp_name = dss_get_default_display_name(); |
748 | struct omap_dss_device *def_dssdev; | ||
749 | int i; | ||
750 | |||
751 | def_dssdev = NULL; | ||
839 | 752 | ||
840 | for (i = 0; i < pdata->num_devices; ++i) { | 753 | for (i = 0; i < pdata->num_devices; ++i) { |
841 | struct omap_dss_device *dssdev = pdata->devices[i]; | 754 | struct omap_dss_device *dssdev = pdata->devices[i]; |
@@ -843,17 +756,69 @@ static void __init venc_probe_pdata(struct platform_device *pdev) | |||
843 | if (dssdev->type != OMAP_DISPLAY_TYPE_VENC) | 756 | if (dssdev->type != OMAP_DISPLAY_TYPE_VENC) |
844 | continue; | 757 | continue; |
845 | 758 | ||
846 | r = venc_init_display(dssdev); | 759 | if (def_dssdev == NULL) |
847 | if (r) { | 760 | def_dssdev = dssdev; |
848 | DSSERR("device %s init failed: %d\n", dssdev->name, r); | 761 | |
849 | continue; | 762 | if (def_disp_name != NULL && |
763 | strcmp(dssdev->name, def_disp_name) == 0) { | ||
764 | def_dssdev = dssdev; | ||
765 | break; | ||
850 | } | 766 | } |
767 | } | ||
768 | |||
769 | return def_dssdev; | ||
770 | } | ||
771 | |||
772 | static void __init venc_probe_pdata(struct platform_device *vencdev) | ||
773 | { | ||
774 | struct omap_dss_device *plat_dssdev; | ||
775 | struct omap_dss_device *dssdev; | ||
776 | int r; | ||
777 | |||
778 | plat_dssdev = venc_find_dssdev(vencdev); | ||
851 | 779 | ||
852 | r = omap_dss_register_device(dssdev, &pdev->dev, i); | 780 | if (!plat_dssdev) |
853 | if (r) | 781 | return; |
854 | DSSERR("device %s register failed: %d\n", | 782 | |
855 | dssdev->name, r); | 783 | dssdev = dss_alloc_and_init_device(&vencdev->dev); |
784 | if (!dssdev) | ||
785 | return; | ||
786 | |||
787 | dss_copy_device_pdata(dssdev, plat_dssdev); | ||
788 | |||
789 | dssdev->channel = OMAP_DSS_CHANNEL_DIGIT; | ||
790 | |||
791 | r = venc_init_display(dssdev); | ||
792 | if (r) { | ||
793 | DSSERR("device %s init failed: %d\n", dssdev->name, r); | ||
794 | dss_put_device(dssdev); | ||
795 | return; | ||
856 | } | 796 | } |
797 | |||
798 | r = dss_add_device(dssdev); | ||
799 | if (r) { | ||
800 | DSSERR("device %s register failed: %d\n", dssdev->name, r); | ||
801 | dss_put_device(dssdev); | ||
802 | return; | ||
803 | } | ||
804 | } | ||
805 | |||
806 | static void __init venc_init_output(struct platform_device *pdev) | ||
807 | { | ||
808 | struct omap_dss_output *out = &venc.output; | ||
809 | |||
810 | out->pdev = pdev; | ||
811 | out->id = OMAP_DSS_OUTPUT_VENC; | ||
812 | out->type = OMAP_DISPLAY_TYPE_VENC; | ||
813 | |||
814 | dss_register_output(out); | ||
815 | } | ||
816 | |||
817 | static void __exit venc_uninit_output(struct platform_device *pdev) | ||
818 | { | ||
819 | struct omap_dss_output *out = &venc.output; | ||
820 | |||
821 | dss_unregister_output(out); | ||
857 | } | 822 | } |
858 | 823 | ||
859 | /* VENC HW IP initialisation */ | 824 | /* VENC HW IP initialisation */ |
@@ -897,17 +862,19 @@ static int __init omap_venchw_probe(struct platform_device *pdev) | |||
897 | 862 | ||
898 | venc_runtime_put(); | 863 | venc_runtime_put(); |
899 | 864 | ||
900 | r = omap_dss_register_driver(&venc_driver); | 865 | r = venc_panel_init(); |
901 | if (r) | 866 | if (r) |
902 | goto err_reg_panel_driver; | 867 | goto err_panel_init; |
903 | 868 | ||
904 | dss_debugfs_create_file("venc", venc_dump_regs); | 869 | dss_debugfs_create_file("venc", venc_dump_regs); |
905 | 870 | ||
871 | venc_init_output(pdev); | ||
872 | |||
906 | venc_probe_pdata(pdev); | 873 | venc_probe_pdata(pdev); |
907 | 874 | ||
908 | return 0; | 875 | return 0; |
909 | 876 | ||
910 | err_reg_panel_driver: | 877 | err_panel_init: |
911 | err_runtime_get: | 878 | err_runtime_get: |
912 | pm_runtime_disable(&pdev->dev); | 879 | pm_runtime_disable(&pdev->dev); |
913 | venc_put_clocks(); | 880 | venc_put_clocks(); |
@@ -916,14 +883,16 @@ err_runtime_get: | |||
916 | 883 | ||
917 | static int __exit omap_venchw_remove(struct platform_device *pdev) | 884 | static int __exit omap_venchw_remove(struct platform_device *pdev) |
918 | { | 885 | { |
919 | omap_dss_unregister_child_devices(&pdev->dev); | 886 | dss_unregister_child_devices(&pdev->dev); |
920 | 887 | ||
921 | if (venc.vdda_dac_reg != NULL) { | 888 | if (venc.vdda_dac_reg != NULL) { |
922 | regulator_put(venc.vdda_dac_reg); | 889 | regulator_put(venc.vdda_dac_reg); |
923 | venc.vdda_dac_reg = NULL; | 890 | venc.vdda_dac_reg = NULL; |
924 | } | 891 | } |
925 | 892 | ||
926 | omap_dss_unregister_driver(&venc_driver); | 893 | venc_panel_exit(); |
894 | |||
895 | venc_uninit_output(pdev); | ||
927 | 896 | ||
928 | pm_runtime_disable(&pdev->dev); | 897 | pm_runtime_disable(&pdev->dev); |
929 | venc_put_clocks(); | 898 | venc_put_clocks(); |
@@ -971,16 +940,10 @@ static struct platform_driver omap_venchw_driver = { | |||
971 | 940 | ||
972 | int __init venc_init_platform_driver(void) | 941 | int __init venc_init_platform_driver(void) |
973 | { | 942 | { |
974 | if (cpu_is_omap44xx()) | ||
975 | return 0; | ||
976 | |||
977 | return platform_driver_probe(&omap_venchw_driver, omap_venchw_probe); | 943 | return platform_driver_probe(&omap_venchw_driver, omap_venchw_probe); |
978 | } | 944 | } |
979 | 945 | ||
980 | void __exit venc_uninit_platform_driver(void) | 946 | void __exit venc_uninit_platform_driver(void) |
981 | { | 947 | { |
982 | if (cpu_is_omap44xx()) | ||
983 | return; | ||
984 | |||
985 | platform_driver_unregister(&omap_venchw_driver); | 948 | platform_driver_unregister(&omap_venchw_driver); |
986 | } | 949 | } |
diff --git a/drivers/video/omap2/dss/venc_panel.c b/drivers/video/omap2/dss/venc_panel.c new file mode 100644 index 000000000000..d55b8784ecfd --- /dev/null +++ b/drivers/video/omap2/dss/venc_panel.c | |||
@@ -0,0 +1,251 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Nokia Corporation | ||
3 | * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> | ||
4 | * | ||
5 | * VENC panel driver | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published by | ||
9 | * the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along with | ||
17 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/err.h> | ||
22 | #include <linux/io.h> | ||
23 | #include <linux/mutex.h> | ||
24 | #include <linux/module.h> | ||
25 | |||
26 | #include <video/omapdss.h> | ||
27 | |||
28 | #include "dss.h" | ||
29 | |||
30 | static struct { | ||
31 | struct mutex lock; | ||
32 | } venc_panel; | ||
33 | |||
34 | static ssize_t display_output_type_show(struct device *dev, | ||
35 | struct device_attribute *attr, char *buf) | ||
36 | { | ||
37 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
38 | const char *ret; | ||
39 | |||
40 | switch (dssdev->phy.venc.type) { | ||
41 | case OMAP_DSS_VENC_TYPE_COMPOSITE: | ||
42 | ret = "composite"; | ||
43 | break; | ||
44 | case OMAP_DSS_VENC_TYPE_SVIDEO: | ||
45 | ret = "svideo"; | ||
46 | break; | ||
47 | default: | ||
48 | return -EINVAL; | ||
49 | } | ||
50 | |||
51 | return snprintf(buf, PAGE_SIZE, "%s\n", ret); | ||
52 | } | ||
53 | |||
54 | static ssize_t display_output_type_store(struct device *dev, | ||
55 | struct device_attribute *attr, const char *buf, size_t size) | ||
56 | { | ||
57 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
58 | enum omap_dss_venc_type new_type; | ||
59 | |||
60 | if (sysfs_streq("composite", buf)) | ||
61 | new_type = OMAP_DSS_VENC_TYPE_COMPOSITE; | ||
62 | else if (sysfs_streq("svideo", buf)) | ||
63 | new_type = OMAP_DSS_VENC_TYPE_SVIDEO; | ||
64 | else | ||
65 | return -EINVAL; | ||
66 | |||
67 | mutex_lock(&venc_panel.lock); | ||
68 | |||
69 | if (dssdev->phy.venc.type != new_type) { | ||
70 | dssdev->phy.venc.type = new_type; | ||
71 | omapdss_venc_set_type(dssdev, new_type); | ||
72 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { | ||
73 | omapdss_venc_display_disable(dssdev); | ||
74 | omapdss_venc_display_enable(dssdev); | ||
75 | } | ||
76 | } | ||
77 | |||
78 | mutex_unlock(&venc_panel.lock); | ||
79 | |||
80 | return size; | ||
81 | } | ||
82 | |||
83 | static DEVICE_ATTR(output_type, S_IRUGO | S_IWUSR, | ||
84 | display_output_type_show, display_output_type_store); | ||
85 | |||
86 | static int venc_panel_probe(struct omap_dss_device *dssdev) | ||
87 | { | ||
88 | /* set default timings to PAL */ | ||
89 | const struct omap_video_timings default_timings = { | ||
90 | .x_res = 720, | ||
91 | .y_res = 574, | ||
92 | .pixel_clock = 13500, | ||
93 | .hsw = 64, | ||
94 | .hfp = 12, | ||
95 | .hbp = 68, | ||
96 | .vsw = 5, | ||
97 | .vfp = 5, | ||
98 | .vbp = 41, | ||
99 | |||
100 | .vsync_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
101 | .hsync_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
102 | |||
103 | .interlace = true, | ||
104 | }; | ||
105 | |||
106 | mutex_init(&venc_panel.lock); | ||
107 | |||
108 | dssdev->panel.timings = default_timings; | ||
109 | |||
110 | return device_create_file(&dssdev->dev, &dev_attr_output_type); | ||
111 | } | ||
112 | |||
113 | static void venc_panel_remove(struct omap_dss_device *dssdev) | ||
114 | { | ||
115 | device_remove_file(&dssdev->dev, &dev_attr_output_type); | ||
116 | } | ||
117 | |||
118 | static int venc_panel_enable(struct omap_dss_device *dssdev) | ||
119 | { | ||
120 | int r; | ||
121 | |||
122 | dev_dbg(&dssdev->dev, "venc_panel_enable\n"); | ||
123 | |||
124 | mutex_lock(&venc_panel.lock); | ||
125 | |||
126 | if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) { | ||
127 | r = -EINVAL; | ||
128 | goto err; | ||
129 | } | ||
130 | |||
131 | omapdss_venc_set_timings(dssdev, &dssdev->panel.timings); | ||
132 | omapdss_venc_set_type(dssdev, dssdev->phy.venc.type); | ||
133 | omapdss_venc_invert_vid_out_polarity(dssdev, | ||
134 | dssdev->phy.venc.invert_polarity); | ||
135 | |||
136 | r = omapdss_venc_display_enable(dssdev); | ||
137 | if (r) | ||
138 | goto err; | ||
139 | |||
140 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
141 | |||
142 | mutex_unlock(&venc_panel.lock); | ||
143 | |||
144 | return 0; | ||
145 | err: | ||
146 | mutex_unlock(&venc_panel.lock); | ||
147 | |||
148 | return r; | ||
149 | } | ||
150 | |||
151 | static void venc_panel_disable(struct omap_dss_device *dssdev) | ||
152 | { | ||
153 | dev_dbg(&dssdev->dev, "venc_panel_disable\n"); | ||
154 | |||
155 | mutex_lock(&venc_panel.lock); | ||
156 | |||
157 | if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED) | ||
158 | goto end; | ||
159 | |||
160 | if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) { | ||
161 | /* suspended is the same as disabled with venc */ | ||
162 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
163 | goto end; | ||
164 | } | ||
165 | |||
166 | omapdss_venc_display_disable(dssdev); | ||
167 | |||
168 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
169 | end: | ||
170 | mutex_unlock(&venc_panel.lock); | ||
171 | } | ||
172 | |||
173 | static int venc_panel_suspend(struct omap_dss_device *dssdev) | ||
174 | { | ||
175 | venc_panel_disable(dssdev); | ||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | static int venc_panel_resume(struct omap_dss_device *dssdev) | ||
180 | { | ||
181 | return venc_panel_enable(dssdev); | ||
182 | } | ||
183 | |||
184 | static void venc_panel_set_timings(struct omap_dss_device *dssdev, | ||
185 | struct omap_video_timings *timings) | ||
186 | { | ||
187 | dev_dbg(&dssdev->dev, "venc_panel_set_timings\n"); | ||
188 | |||
189 | mutex_lock(&venc_panel.lock); | ||
190 | |||
191 | omapdss_venc_set_timings(dssdev, timings); | ||
192 | dssdev->panel.timings = *timings; | ||
193 | |||
194 | mutex_unlock(&venc_panel.lock); | ||
195 | } | ||
196 | |||
197 | static int venc_panel_check_timings(struct omap_dss_device *dssdev, | ||
198 | struct omap_video_timings *timings) | ||
199 | { | ||
200 | dev_dbg(&dssdev->dev, "venc_panel_check_timings\n"); | ||
201 | |||
202 | return omapdss_venc_check_timings(dssdev, timings); | ||
203 | } | ||
204 | |||
205 | static u32 venc_panel_get_wss(struct omap_dss_device *dssdev) | ||
206 | { | ||
207 | dev_dbg(&dssdev->dev, "venc_panel_get_wss\n"); | ||
208 | |||
209 | return omapdss_venc_get_wss(dssdev); | ||
210 | } | ||
211 | |||
212 | static int venc_panel_set_wss(struct omap_dss_device *dssdev, u32 wss) | ||
213 | { | ||
214 | dev_dbg(&dssdev->dev, "venc_panel_set_wss\n"); | ||
215 | |||
216 | return omapdss_venc_set_wss(dssdev, wss); | ||
217 | } | ||
218 | |||
219 | static struct omap_dss_driver venc_driver = { | ||
220 | .probe = venc_panel_probe, | ||
221 | .remove = venc_panel_remove, | ||
222 | |||
223 | .enable = venc_panel_enable, | ||
224 | .disable = venc_panel_disable, | ||
225 | .suspend = venc_panel_suspend, | ||
226 | .resume = venc_panel_resume, | ||
227 | |||
228 | .get_resolution = omapdss_default_get_resolution, | ||
229 | .get_recommended_bpp = omapdss_default_get_recommended_bpp, | ||
230 | |||
231 | .set_timings = venc_panel_set_timings, | ||
232 | .check_timings = venc_panel_check_timings, | ||
233 | |||
234 | .get_wss = venc_panel_get_wss, | ||
235 | .set_wss = venc_panel_set_wss, | ||
236 | |||
237 | .driver = { | ||
238 | .name = "venc", | ||
239 | .owner = THIS_MODULE, | ||
240 | }, | ||
241 | }; | ||
242 | |||
243 | int venc_panel_init(void) | ||
244 | { | ||
245 | return omap_dss_register_driver(&venc_driver); | ||
246 | } | ||
247 | |||
248 | void venc_panel_exit(void) | ||
249 | { | ||
250 | omap_dss_unregister_driver(&venc_driver); | ||
251 | } | ||