mx51 TVOUT分析

1397 static int __init enable_tve_setup(char *options)
1398 {
1399     g_enable_tve = true;
1400
1401     return 1;
1402 }
1403 __setup("tve", enable_tve_setup);

一般情况,freescale会推荐在kernel命令行参数中使能TVE, 这个函数就是处理kernel传入的参数

'init=/init androidboot.console=ttymxc0 di1_primary video=mxcdi1fb:YUV444, 720x576-i@50 tve'


1198 static int tve_probe(struct platform_device *pdev)

1199 {
1200     int ret, i, primary = 0;
1201     struct resource *res;
1202     struct tve_platform_data *plat_data = pdev->dev.platform_data;
1203     u32 conf_reg;
1204
1205     if (g_enable_tve == false)
1206         return -EPERM;
1207
1208     INIT_LIST_HEAD(&tve_modelist.list);
1209
1210     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1211     if (res == NULL)
1212         return -ENOMEM;
1213
1214     tve.pdev = pdev;
1215     tve.base = ioremap(res->start, res->end - res->start);
1216
1217     tve.irq = platform_get_irq(pdev, 0);
1218     if (tve.irq < 0) {
1219         ret = tve.irq;
1220         goto err0;
1221     }
1222
1223     ret = request_irq(tve.irq, tve_detect_handler, 0, pdev->name, pdev);
1224     if (ret < 0)
1225         goto err0;
1226
1227     ret = device_create_file(&pdev->dev, &dev_attr_headphone);
1228     if (ret < 0)
1229         goto err1;
1230
1231     for (i = 0; i < num_registered_fb; i++) {
1232         if (strcmp(registered_fb[i]->fix.id, "DISP3 BG - DI1") == 0) {
1233             tve_fbi = registered_fb[i];
1234             if (i == 0) {
1235                 pr_info("TVE as primary display\n");
1236                 primary = 1;
1237                 acquire_console_sem();
1238                 fb_blank(tve_fbi, FB_BLANK_POWERDOWN);
1239                 release_console_sem();
1240             }
1241             break;
1242         }
1243     }

1215 映射TVE寄存器地址到,结果保存到tve.base中

1217~1225 注册Cable Detect handler

1227 创建headphone属性文件,可以通过cat /sys/devices/platform/tve.0/headphone查看当前 cable 状态。

1231~1243 如果在kernel cmdline中指定了di1_primary,那么registered_fb[0] 的id就是"DISP3 BG - DI1",此时关闭fb_blank

1257 ~ 1266 获取di1和TVE的时钟

1267 ~ 1269 设置TVE的时钟rate,设置tve_clk1为di1_clk的父亲,这样启动di1就会为tve时钟上电;

1269 使能tve clk,这样才能操作tve的寄存器。

1271 ~ 1278 获取tve 版本;根据tve 的版本,来选择要操作的寄存器集合,

1292 ~ 1306 video_modes PAL, NTSC, 720P 是rev1和rev2都支持的video mode,rev2支持其他集中模式,XGA和SXGA仅在53上支持。

1309 初始化一个动作队列,这个工作队列是用来处理cable detect

1310 ~ 1313 设置cable detect register

1325 已经操作完TVE的寄存器,可以关闭clk了

1327 注册一个notifier callback,这样在fb event事件发生时就可以调用这个callback

1334  TVE是primary frame buffer,所以要显示logo

1343 不知道为什么要设置为 var.yres * 3 以后回来再看

1348~1356 关闭frame buffer再打开frame buffer


1179 static int _tve_get_revision(void)
1180 {
1181     u32 conf_reg;
1182     u32 rev = 0;
1183
1184     /* find out TVE rev based on the base addr default value
1185      * can be used at the init/probe ONLY */
1186     conf_reg = __raw_readl(tve.base);
1187     switch (conf_reg) {
1188     case 0x00842000:
1189         rev = 1;
1190         break;
1191     case 0x00100000:
1192         rev = 2;
1193         break;
1194     }
1195     return rev;
1196 }

通过读取0xBASE_0000寄存器的初始缺省值来获取TVE的版本号


1147 static ssize_t show_headphone(struct device *dev,
1148         struct device_attribute *attr, char *buf)
1149 {
1150     int detect;
1151
1152     if (!enabled) {
1153         strcpy(buf, "tve power off\n");
1154         return strlen(buf);
1155     }
1156
1157     detect = tve_update_detect_status();
1158
1159     if (detect == 0)
1160         strcpy(buf, "none\n");
1161     else if (detect == 1)
1162         strcpy(buf, "cvbs\n");
1163     else if (detect == 2)
1164         strcpy(buf, "headset\n");
1165     else if (detect == 3)
1166         strcpy(buf, "component\n");
1167     else
1168         strcpy(buf, "svideo\n");
1169
1170     return strlen(buf);
1171 }
这个函数是一个sys接口的show函数,用来显示当前cable的插入状态,cat /sys/devices/platform/tve.0/headphone将显示相应状态

1157是真正的cable检测函数


 632 static int tve_update_detect_status(void)
 633 {
 634     int old_detect = tve.detect;
 635     u32 stat_lm, stat_sm, stat;
 636     u32 int_ctl;
 637     u32 cd_cont_reg;
 638     u32 timeout = 40;
 639     unsigned long lock_flags;
 640
 641     spin_lock_irqsave(&tve_lock, lock_flags);
 642
 643     if (!enabled) {
 644         pr_warning("Warning: update tve status while it disabled!\n");
 645         tve.detect = 0;
 646         goto done;
 647     }
 648
 649     int_ctl = __raw_readl(tve.base + tve_regs->tve_int_cont_reg);
 650     cd_cont_reg = __raw_readl(tve.base + tve_regs->tve_cd_cont_reg);
 651
 652     if ((cd_cont_reg & 0x1) == 0) {
 653         pr_warning("Warning: pls enable TVE CD first!\n");
 654         goto done;
 655     }
 656
 657     stat = __raw_readl(tve.base + tve_regs->tve_stat_reg);
 658     while (((stat & CD_MON_END_INT) == 0) && (timeout > 0)) {
 659         spin_unlock_irqrestore(&tve_lock, lock_flags);
 660         msleep(2);
 661         spin_lock_irqsave(&tve_lock, lock_flags);
 662         timeout -= 2;
 663         if (!enabled) {
 664             pr_warning("Warning: update tve status while it disabled!\n");
 665             tve.detect = 0;
 666             goto done;
 667         } else
 668             stat = __raw_readl(tve.base + tve_regs->tve_stat_reg);
 669     }
 670     if (((stat & CD_MON_END_INT) == 0) && (timeout <= 0)) {
 671         pr_warning("Warning: get detect result without CD_MON_END_INT!\n");
 672         goto done;
 673     }
 674
 675     stat = stat >> tve_reg_fields->cd_ch_stat_offset;
 676     stat_lm = stat & (CD_CH_0_LM_ST | CD_CH_1_LM_ST | CD_CH_2_LM_ST);
 677     if ((stat_lm == (CD_CH_0_LM_ST | CD_CH_1_LM_ST | CD_CH_2_LM_ST)) &&
 678         ((stat & (CD_CH_0_SM_ST | CD_CH_1_SM_ST | CD_CH_2_SM_ST)) == 0)
 679         ) {
 680             tve.detect = 3;
 681             tve.output_mode = YPBPR;
 682     } else if ((stat_lm == (CD_CH_0_LM_ST | CD_CH_1_LM_ST)) &&
 683         ((stat & (CD_CH_0_SM_ST | CD_CH_1_SM_ST)) == 0)) {
 684             tve.detect = 4;
 685             tve.output_mode = SVIDEO;
 686     } else if (stat_lm == CD_CH_0_LM_ST) {
 687         stat_sm = stat & CD_CH_0_SM_ST;
 688         if (stat_sm != 0) {
 689             /* headset */
 690             tve.detect = 2;
 691             tve.output_mode = TV_OFF;
 692         } else {
 693             tve.detect = 1;
 694             tve.output_mode = CVBS0;
 695         }
 696     } else if (stat_lm == CD_CH_2_LM_ST) {
 697         stat_sm = stat & CD_CH_2_SM_ST;
 698         if (stat_sm != 0) {
 699             /* headset */
 700             tve.detect = 2;
 701             tve.output_mode = TV_OFF;
 702         } else {
 703             tve.detect = 1;
 704             tve.output_mode = CVBS2;
 705         }
 706     } else {
 707         /* none */
 708         tve.detect = 0;
 709         tve.output_mode = TV_OFF;
 710     }
 711
 712     tve_set_tvout_mode(tve.output_mode);
 713
 714     /* clear interrupt */
 715     __raw_writel(CD_MON_END_INT | CD_LM_INT | CD_SM_INT,
 716             tve.base + tve_regs->tve_stat_reg);
 717
 718     __raw_writel(int_ctl | CD_SM_INT | CD_LM_INT,
 719             tve.base + tve_regs->tve_int_cont_reg);
 720
 721     if (old_detect != tve.detect)
 722         sysfs_notify(&tve.pdev->dev.kobj, NULL, "headphone");
 723
 724     dev_dbg(&tve.pdev->dev, "detect = %d mode = %d\n",
 725             tve.detect, tve.output_mode);
 726 done:
 727     spin_unlock_irqrestore(&tve_lock, lock_flags);
 728     return tve.detect;
 729 }

643 ~ 647 TVE当前是disable的,所以不会做检测,直接返回tve.detect=0

650 ~655 应该使能CD_EN

657 ~ 669 每2ms检测一次tve_stat_reg,直到CD_MON_END_INT发生或者timeout

670 ~ 673 无CD_MON_END_INT中断发生,返回

675~710 根据tve_state_reg中的CD_CH_x_LM_ST和CD_CH_x_SM_ST来决定cable的插入状态

712 tve_set_tvout_mode是根据当前的cable 状态来调整tve out 模式

715 ~ 717 清空tve_stat_reg的cable detect状态位,写1清空

718 ~ 719 使能CD_SM_INT和CD_LM_INT,检测 cable的插拔

721 ~ 722 上报headphone事件给poll这个headphone文件描述符的进程


 913 int tve_fb_event(struct notifier_block *nb, unsigned long val, void *v)
 914 {
 915     struct fb_event *event = v;
 916     struct fb_info *fbi = event->info;
 917
 918     if (strcmp(fbi->fix.id, "DISP3 BG - DI1"))
 919         return 0;
 920
 921     switch (val) {
 922     case FB_EVENT_FB_REGISTERED:
 923         pr_debug("fb registered event\n");
 924         if (tve_fbi != NULL)
 925             break;
 926
 927         tve_fbi = fbi;
 928         fb_add_videomode(&video_modes[0], &tve_modelist.list);
 929         fb_add_videomode(&video_modes[1], &tve_modelist.list);
 930         fb_add_videomode(&video_modes[2], &tve_modelist.list);
 931         if (tve.revision == 2) {
 932             fb_add_videomode(&video_modes[3], &tve_modelist.list);
 933             fb_add_videomode(&video_modes[4], &tve_modelist.list);
 934             fb_add_videomode(&video_modes[5], &tve_modelist.list);
 935             fb_add_videomode(&video_modes[6], &tve_modelist.list);
 936             fb_add_videomode(&video_modes[7], &tve_modelist.list);
 937             fb_add_videomode(&video_modes[8], &tve_modelist.list);
 938             if (cpu_is_mx53()) {
 939                 fb_add_videomode(&video_modes[9], &tve_modelist.list);
 940                 fb_add_videomode(&video_modes[10], &tve_modelist.list);
 941             }
 942         }
 943         break;
 944     case FB_EVENT_MODE_CHANGE:
 945     {
 946         if (tve_fbi != fbi)
 947             break;
 948
 949         fbi->mode = (struct fb_videomode *)fb_match_mode(&tve_fbi->var,
 950                 &tve_modelist.list);
 951
 952         if (!fbi->mode) {
 953             pr_warning("TVE: can not find mode for xres=%d, yres=%d\n",
 954                     fbi->var.xres, fbi->var.yres);
 955             tve_disable();
 956             tve.cur_mode = TVOUT_FMT_OFF;
 957             return 0;
 958         }
 959
 960         pr_debug("TVE: fb mode change event: xres=%d, yres=%d\n",
 961              fbi->mode->xres, fbi->mode->yres);
 962
 963         if (fb_mode_is_equal(fbi->mode, &video_modes[0])) {
 964             tve_set_di_fmt(fbi, IPU_PIX_FMT_YUV444);
 965             tve_disable();
 966             tve_setup(TVOUT_FMT_NTSC);
 967             if (tve.blank == FB_BLANK_UNBLANK)
 968                 tve_enable();
 969         } else if (fb_mode_is_equal(fbi->mode, &video_modes[1])) {
 970             tve_set_di_fmt(fbi, IPU_PIX_FMT_YUV444);
 971             tve_disable();
 972             tve_setup(TVOUT_FMT_PAL);
 973             if (tve.blank == FB_BLANK_UNBLANK)
 974                 tve_enable();
 975         } else if (fb_mode_is_equal(fbi->mode, &video_modes[2])) {
 976             tve_set_di_fmt(fbi, IPU_PIX_FMT_YUV444);
 977             tve_disable();
 978             tve_setup(TVOUT_FMT_720P60);
 979             if (tve.blank == FB_BLANK_UNBLANK)
 980                 tve_enable();
 981         } else if (fb_mode_is_equal(fbi->mode, &video_modes[3])) {
 982             tve_set_di_fmt(fbi, IPU_PIX_FMT_YUV444);
 983             tve_disable();
 984             tve_setup(TVOUT_FMT_720P30);
 985             if (tve.blank == FB_BLANK_UNBLANK)
 986                 tve_enable();
 987         } else if (fb_mode_is_equal(fbi->mode, &video_modes[4])) {
 988             tve_set_di_fmt(fbi, IPU_PIX_FMT_YUV444);
 989             tve_disable();
 990             tve_setup(TVOUT_FMT_1080I60);
 991             if (tve.blank == FB_BLANK_UNBLANK)
 992                 tve_enable();
 993         } else if (fb_mode_is_equal(fbi->mode, &video_modes[5])) {
 994             tve_set_di_fmt(fbi, IPU_PIX_FMT_YUV444);
 995             tve_disable();
 996             tve_setup(TVOUT_FMT_1080I50);
 997             if (tve.blank == FB_BLANK_UNBLANK)
 998                 tve_enable();
 999         } else if (fb_mode_is_equal(fbi->mode, &video_modes[6])) {
1000             tve_set_di_fmt(fbi, IPU_PIX_FMT_YUV444);
1001             tve_disable();
1002             tve_setup(TVOUT_FMT_1080P30);
1003             if (tve.blank == FB_BLANK_UNBLANK)
1004                 tve_enable();
1005         } else if (fb_mode_is_equal(fbi->mode, &video_modes[7])) {
1006             tve_set_di_fmt(fbi, IPU_PIX_FMT_YUV444);
1007             tve_disable();
1008             tve_setup(TVOUT_FMT_1080P25);
1009             if (tve.blank == FB_BLANK_UNBLANK)
1010                 tve_enable();
1011         } else if (fb_mode_is_equal(fbi->mode, &video_modes[8])) {
1012             tve_set_di_fmt(fbi, IPU_PIX_FMT_YUV444);
1013             tve_disable();
1014             tve_setup(TVOUT_FMT_1080P24);
1015             if (tve.blank == FB_BLANK_UNBLANK)
1016                 tve_enable();
1017         } else if (fb_mode_is_equal(fbi->mode, &video_modes[9])) {
1018             tve_set_di_fmt(fbi, IPU_PIX_FMT_GBR24);
1019             tve_disable();
1020             tve_setup(TVOUT_FMT_VGA_XGA);
1021             if (tve.blank == FB_BLANK_UNBLANK) {
1022                 tve_enable();
1023                 ipu_set_vga_delay(fbi, 1421, 803);
1024             }
1025         } else if (fb_mode_is_equal(fbi->mode, &video_modes[10])) {
1026             tve_set_di_fmt(fbi, IPU_PIX_FMT_GBR24);
1027             tve_disable();
1028             tve_setup(TVOUT_FMT_VGA_SXGA);
1029             if (tve.blank == FB_BLANK_UNBLANK) {
1030                 tve_enable();
1031                 ipu_set_vga_delay(fbi, 1504, 1030);
1032             }
1033         } else {
1034             tve_disable();
1035             tve_setup(TVOUT_FMT_OFF);
1036         }
1037         break;
1038     }
1039     case FB_EVENT_BLANK:
1040         if ((tve_fbi != fbi) || (fbi->mode == NULL))
1041             return 0;
1042
1043         if (*((int *)event->data) == FB_BLANK_UNBLANK) {
1044             if (tve.blank != FB_BLANK_UNBLANK) {
1045                 if (fb_mode_is_equal(fbi->mode, &video_modes[0])) {
1046                     if (tve.cur_mode != TVOUT_FMT_NTSC) {
1047                         tve_disable();
1048                         tve_setup(TVOUT_FMT_NTSC);
1049                     }
1050                     tve_enable();
1051                 } else if (fb_mode_is_equal(fbi->mode,
1052                             &video_modes[1])) {
1053                     if (tve.cur_mode != TVOUT_FMT_PAL) {
1054                         tve_disable();
1055                         tve_setup(TVOUT_FMT_PAL);
1056                     }
1057                     tve_enable();
1058                 } else if (fb_mode_is_equal(fbi->mode,
1059                             &video_modes[2])) {
1060                     if (tve.cur_mode != TVOUT_FMT_720P60) {
1061                         tve_disable();
1062                         tve_setup(TVOUT_FMT_720P60);
1063                     }
1064                     tve_enable();
1065                 } else if (fb_mode_is_equal(fbi->mode,
1066                             &video_modes[3])) {
1067                     if (tve.cur_mode != TVOUT_FMT_720P30) {
1068                         tve_disable();
1069                         tve_setup(TVOUT_FMT_720P30);
1070                     }
1071                     tve_enable();
1072                 } else if (fb_mode_is_equal(fbi->mode,
1073                             &video_modes[4])) {
1074                     if (tve.cur_mode != TVOUT_FMT_1080I60) {
1075                         tve_disable();
1076                         tve_setup(TVOUT_FMT_1080I60);
1077                     }
1078                     tve_enable();
1079                 } else if (fb_mode_is_equal(fbi->mode,
1080                             &video_modes[5])) {
1081                     if (tve.cur_mode != TVOUT_FMT_1080I50) {
1082                         tve_disable();
1083                         tve_setup(TVOUT_FMT_1080I50);
1084                     }
1085                     tve_enable();
1086                 } else if (fb_mode_is_equal(fbi->mode,
1087                             &video_modes[6])) {
1088                     if (tve.cur_mode != TVOUT_FMT_1080P30) {
1089                         tve_disable();
1090                         tve_setup(TVOUT_FMT_1080P30);
1091                     }
1092                     tve_enable();
1093                 } else if (fb_mode_is_equal(fbi->mode,
1094                             &video_modes[7])) {
1095                     if (tve.cur_mode != TVOUT_FMT_1080P25) {
1096                         tve_disable();
1097                         tve_setup(TVOUT_FMT_1080P25);
1098                     }
1099                     tve_enable();
1100                 } else if (fb_mode_is_equal(fbi->mode,
1101                             &video_modes[8])) {
1102                     if (tve.cur_mode != TVOUT_FMT_1080P24) {
1103                         tve_disable();
1104                         tve_setup(TVOUT_FMT_1080P24);
1105                     }
1106                     tve_enable();
1107                 } else if (fb_mode_is_equal(fbi->mode,
1108                             &video_modes[9])) {
1109                     if (tve.cur_mode != TVOUT_FMT_VGA_XGA) {
1110                         tve_disable();
1111                         tve_setup(TVOUT_FMT_VGA_XGA);
1112                     }
1113                     tve_enable();
1114                     ipu_set_vga_delay(fbi, 1421, 803);
1115                 } else if (fb_mode_is_equal(fbi->mode,
1116                             &video_modes[10])) {
1117                     if (tve.cur_mode != TVOUT_FMT_VGA_SXGA) {
1118                         tve_disable();
1119                         tve_setup(TVOUT_FMT_VGA_SXGA);
1120                     }
1121                     tve_enable();
1122                     ipu_set_vga_delay(fbi, 1504, 1030);
1123                 } else {
1124                     tve_setup(TVOUT_FMT_OFF);
1125                 }
1126                 tve.blank = FB_BLANK_UNBLANK;
1127             }
1128         } else {
1129             tve_disable();
1130             tve.blank = FB_BLANK_POWERDOWN;
1131         }
1132         break;
1133     case FB_EVENT_SUSPEND:
1134         tve_suspend();
1135         break;
1136     case FB_EVENT_RESUME:
1137         tve_resume(fbi);
1138         break;
1139     }
1140     return 0;
1141 }

918 ~ 919 因为tve_fb_event被调用时不知道是不是tve的事件,如果不是,不做处理

922 ~ 943 FB_EVENT_FB_REGISTERED,那么要把NTSC PAL 720P加入到mode_list中,如果是rev2再加入一些mode,如果是mx53还支持XGA SXGA模式

944 ~ 1038 处理模式发生变化的情况

949 ~ 958 先检查新mode是否在tve_modelist中,不在的话则tve_disable

963 ~ 1032 1. 调用tve_set_di_fmt设置display input format; 2. disable tve; 3. tve_setup设置TVE 输出模式; 4.如果tve_fbi是UNBLANK的,那么还要调用tve_enable使能TVE

1033 ~ 1036 disable TVE,设置TVE


1039     case FB_EVENT_BLANK:
1040         if ((tve_fbi != fbi) || (fbi->mode == NULL))
1041             return 0;
1042
1043         if (*((int *)event->data) == FB_BLANK_UNBLANK) {
1044             if (tve.blank != FB_BLANK_UNBLANK) {
1045                 if (fb_mode_is_equal(fbi->mode, &video_modes[0])) {
1046                     if (tve.cur_mode != TVOUT_FMT_NTSC) {
1047                         tve_disable();
1048                         tve_setup(TVOUT_FMT_NTSC);
1049                     }
1050                     tve_enable();
1051                 } else if (fb_mode_is_equal(fbi->mode,
1052                             &video_modes[1])) {
1053                     if (tve.cur_mode != TVOUT_FMT_PAL) {
1054                         tve_disable();
1055                         tve_setup(TVOUT_FMT_PAL);
1056                     }
1057                     tve_enable();
1058                 } else if (fb_mode_is_equal(fbi->mode,
1059                             &video_modes[2])) {
1060                     if (tve.cur_mode != TVOUT_FMT_720P60) {
1061                         tve_disable();
1062                         tve_setup(TVOUT_FMT_720P60);
1063                     }
1064                     tve_enable();
1065                 } else if (fb_mode_is_equal(fbi->mode,
1066                             &video_modes[3])) {
1067                     if (tve.cur_mode != TVOUT_FMT_720P30) {
1068                         tve_disable();
1069                         tve_setup(TVOUT_FMT_720P30);
1070                     }
1071                     tve_enable();
1072                 } else if (fb_mode_is_equal(fbi->mode,
1073                             &video_modes[4])) {
1074                     if (tve.cur_mode != TVOUT_FMT_1080I60) {
1075                         tve_disable();
1076                         tve_setup(TVOUT_FMT_1080I60);
1077                     }
1078                     tve_enable();
1079                 } else if (fb_mode_is_equal(fbi->mode,
1080                             &video_modes[5])) {
1081                     if (tve.cur_mode != TVOUT_FMT_1080I50) {
1082                         tve_disable();
1083                         tve_setup(TVOUT_FMT_1080I50);
1084                     }
1085                     tve_enable();
1086                 } else if (fb_mode_is_equal(fbi->mode,
1087                             &video_modes[6])) {
1088                     if (tve.cur_mode != TVOUT_FMT_1080P30) {
1089                         tve_disable();
1090                         tve_setup(TVOUT_FMT_1080P30);
1091                     }
1092                     tve_enable();
1093                 } else if (fb_mode_is_equal(fbi->mode,
1094                             &video_modes[7])) {
1095                     if (tve.cur_mode != TVOUT_FMT_1080P25) {
1096                         tve_disable();
1097                         tve_setup(TVOUT_FMT_1080P25);
1098                     }
1099                     tve_enable();
1100                 } else if (fb_mode_is_equal(fbi->mode,
1101                             &video_modes[8])) {
1102                     if (tve.cur_mode != TVOUT_FMT_1080P24) {
1103                         tve_disable();
1104                         tve_setup(TVOUT_FMT_1080P24);
1105                     }
1106                     tve_enable();
1107                 } else if (fb_mode_is_equal(fbi->mode,
1108                             &video_modes[9])) {
1109                     if (tve.cur_mode != TVOUT_FMT_VGA_XGA) {
1110                         tve_disable();
1111                         tve_setup(TVOUT_FMT_VGA_XGA);
1112                     }
1113                     tve_enable();
1114                     ipu_set_vga_delay(fbi, 1421, 803);
1115                 } else if (fb_mode_is_equal(fbi->mode,
1116                             &video_modes[10])) {
1117                     if (tve.cur_mode != TVOUT_FMT_VGA_SXGA) {
1118                         tve_disable();
1119                         tve_setup(TVOUT_FMT_VGA_SXGA);
1120                     }
1121                     tve_enable();
1122                     ipu_set_vga_delay(fbi, 1504, 1030);
1123                 } else {
1124                     tve_setup(TVOUT_FMT_OFF);
1125                 }
1126                 tve.blank = FB_BLANK_UNBLANK;
1127             }
1128         } else {
1129             tve_disable();
1130             tve.blank = FB_BLANK_POWERDOWN;
1131         }
1132         break;
1133     case FB_EVENT_SUSPEND:
1134         tve_suspend();
1135         break;
1136     case FB_EVENT_RESUME:
1137         tve_resume(fbi);
1138         break;
1139     }
1140     return 0;
1141 }


1128 ~ 1131 unblank操作,dsiable tve设置tve.blank为FB_BLANK_POWERDOWN

1043 ~ 1127 FB_BLANK_UNBLANK并且TVE当前状态不是FB_BLANK_UNBLANK,如果当前mode不是ffbi的当前模式,那么设置为当前模式,最后还要使能TVE


 821 static inline void tve_set_di_fmt(struct fb_info *fbi, unsigned int fmt)
 822 {
 823     mm_segment_t old_fs;
 824
 825     if (fbi->fbops->fb_ioctl) {
 826         old_fs = get_fs();
 827         set_fs(KERNEL_DS);
 828         fbi->fbops->fb_ioctl(fbi, MXCFB_SET_DIFMT, (unsigned long)&fmt);
 829         set_fs(old_fs);
 830     }
 831 }

该函数调用fbi->fbops->fb_ioctl设置 display format,由于fmt是内核空间,而fb_ioctl系统调用会确定&fmt是用户空间,

所以需要把当前的fs设置为内核空间,避开这个检查。参见http://blog.chinaunix.net/space.php?uid=20564848&do=blog&cuid=2097853

 

771 static irqreturn_t tve_detect_handler(int irq, void *data)
 772 {
 773     u32 int_ctl = __raw_readl(tve.base + tve_regs->tve_int_cont_reg);
 774
 775     /* disable INT first */
 776     int_ctl &= ~(CD_SM_INT | CD_LM_INT | CD_MON_END_INT);
 777     __raw_writel(int_ctl, tve.base + tve_regs->tve_int_cont_reg);
 778
 779     __raw_writel(CD_MON_END_INT | CD_LM_INT | CD_SM_INT,
 780             tve.base + tve_regs->tve_stat_reg);
 781
 782     schedule_delayed_work(&tve.cd_work, msecs_to_jiffies(1000));
 783
 784     return IRQ_HANDLED;
 785 }


中断处理函数,首先disable INT清除中断状态位,然后清除掉tve_stat_reg中相应的状态位,这里我奇怪为什么要清除CD_MON_END_INT,因为tve_update_detect_status要使用这个标志呀


 615 static void tve_disable(void)
 616 {
 617     u32 reg;
 618     unsigned long lock_flags;
 619
 620     spin_lock_irqsave(&tve_lock, lock_flags);
 621     if (enabled) {
 622         enabled = 0;
 623         reg = __raw_readl(tve.base + tve_regs->tve_com_conf_reg);
 624         __raw_writel(reg & ~TVE_ENABLE & ~TVE_IPU_CLK_ENABLE,
 625                 tve.base + tve_regs->tve_com_conf_reg);
 626         clk_disable(tve.clk);
 627         pr_debug("TVE power off.\n");
 628     }
 629     spin_unlock_irqrestore(&tve_lock, lock_flags);
 630 }
关闭TVE和TVE IPU clock,关闭tve.clk时钟,置位enable为0


 578 static void tve_enable(void)
 579 {
 580     u32 reg;
 581     unsigned long lock_flags;
 582
 583     spin_lock_irqsave(&tve_lock, lock_flags);
 584     if (!enabled) {
 585         enabled = 1;
 586         clk_enable(tve.clk);
 587         reg = __raw_readl(tve.base + tve_regs->tve_com_conf_reg);
 588         __raw_writel(reg | TVE_IPU_CLK_ENABLE | TVE_ENABLE,
 589                     tve.base + tve_regs->tve_com_conf_reg);
 590         pr_debug("TVE power on.\n");
 591     }
 592
 593     if (is_vga_mode()) {
 594         /* disable interrupt */
 595         pr_debug("TVE VGA disable cable detect.\n");
 596         __raw_writel(0xffffffff, tve.base + tve_regs->tve_stat_reg);
 597         __raw_writel(0, tve.base + tve_regs->tve_int_cont_reg);
 598     } else {
 599         /* enable interrupt */
 600         pr_debug("TVE TVE enable cable detect.\n");
 601         __raw_writel(0xffffffff, tve.base + tve_regs->tve_stat_reg);
 602         __raw_writel(CD_SM_INT | CD_LM_INT | CD_MON_END_INT,
 603                 tve.base + tve_regs->tve_int_cont_reg);
 604     }
 605
 606     spin_unlock_irqrestore(&tve_lock, lock_flags);
 607
 608     tve_dump_regs();
 609 }

584 ~ 591 使能tve.clk,使能TVE以及TVE IPU clock

593 ~ 598 对于TVE VGA模式关闭cable detect

598 ~ 604 对于其他的模式使能cable detect


 415 static int tve_setup(int mode)
 416 {
 417     u32 reg;
 418     struct clk *tve_parent_clk;
 419     unsigned long parent_clock_rate = 216000000, di1_clock_rate = 27000000;
 420     unsigned long tve_clock_rate = 216000000;
 421     unsigned long lock_flags;
 422
 423     if (tve.cur_mode == mode)
 424         return 0;
 425
 426     spin_lock_irqsave(&tve_lock, lock_flags);
 427
 428     switch (mode) {
 429     case TVOUT_FMT_PAL:
 430     case TVOUT_FMT_NTSC:
 431         parent_clock_rate = 216000000;
 432         di1_clock_rate = 27000000;
 433         break;
 434     case TVOUT_FMT_720P60:
 435     case TVOUT_FMT_1080I60:
 436     case TVOUT_FMT_1080I50:
 437     case TVOUT_FMT_720P30:
 438     case TVOUT_FMT_1080P30:
 439     case TVOUT_FMT_1080P25:
 440     case TVOUT_FMT_1080P24:
 441         parent_clock_rate = 297000000;
 442         tve_clock_rate = 297000000;
 443         di1_clock_rate = 74250000;
 444         break;
 445     case TVOUT_FMT_VGA_XGA:
 446         parent_clock_rate = 260000000;
 447         tve_clock_rate = 130000000;
 448         di1_clock_rate = 65000000;
 449         break;
 450     case TVOUT_FMT_VGA_SXGA:
 451         parent_clock_rate = 216000000;
 452         di1_clock_rate = 108000000;
 453         break;
 454     }
 455     if (enabled)
 456         clk_disable(tve.clk);
 457
 458     tve_parent_clk = clk_get_parent(tve.clk);
 459
 460     clk_set_rate(tve_parent_clk, parent_clock_rate);
 461
 462     tve_clock_rate = clk_round_rate(tve.clk, tve_clock_rate);
 463     clk_set_rate(tve.clk, tve_clock_rate);
 464
 465     clk_enable(tve.clk);
 466     di1_clock_rate = clk_round_rate(tve.di_clk, di1_clock_rate);
 467     clk_set_rate(tve.di_clk, di1_clock_rate);
 468
 469     tve.cur_mode = mode;
 470
 471     /* select output video format */
 472     if (mode == TVOUT_FMT_PAL) {
 473         tve_disable_vga_mode();
 474         tve_set_tvout_mode(YPBPR);
 475         reg = __raw_readl(tve.base + tve_regs->tve_com_conf_reg);
 476         reg = (reg & ~TVE_STAND_MASK) | TVE_PAL_STAND;
 477         __raw_writel(reg, tve.base + tve_regs->tve_com_conf_reg);
 478         pr_debug("TVE: change to PAL video\n");
 479     } else if (mode == TVOUT_FMT_NTSC) {
 480         tve_disable_vga_mode();
 481         tve_set_tvout_mode(YPBPR);
 482         reg = __raw_readl(tve.base + tve_regs->tve_com_conf_reg);
 483         reg = (reg & ~TVE_STAND_MASK) | TVE_NTSC_STAND;
 484         __raw_writel(reg, tve.base + tve_regs->tve_com_conf_reg);
 485         pr_debug("TVE: change to NTSC video\n");
 486     } else if (mode == TVOUT_FMT_720P60) {
 487         tve_disable_vga_mode();
 488         if (!_is_tvout_mode_hd_compatible()) {
 489             tve_set_tvout_mode(YPBPR);
 490             pr_debug("The TV out mode is HD incompatible. Setting to YPBPR.");
 491         }
 492         reg = __raw_readl(tve.base + tve_regs->tve_com_conf_reg);
 493         reg = (reg & ~TVE_STAND_MASK) | TVE_HD720P60_STAND;
 494         __raw_writel(reg, tve.base + tve_regs->tve_com_conf_reg);
 495         pr_debug("TVE: change to 720P60 video\n");
 496     } else if (mode == TVOUT_FMT_720P30) {
 497         tve_disable_vga_mode();
 498         if (!_is_tvout_mode_hd_compatible()) {
 499             tve_set_tvout_mode(YPBPR);
 500             pr_debug("The TV out mode is HD incompatible. Setting to YPBPR.");
 501         }
 502         reg = __raw_readl(tve.base + tve_regs->tve_com_conf_reg);
 503         reg = (reg & ~TVE_STAND_MASK) | TVE_HD720P30_STAND;
 504         __raw_writel(reg, tve.base + tve_regs->tve_com_conf_reg);
 505         pr_debug("TVE: change to 720P30 video\n");
 506     } else if (mode == TVOUT_FMT_1080I60) {
 507         tve_disable_vga_mode();
 508         if (!_is_tvout_mode_hd_compatible()) {
 509             tve_set_tvout_mode(YPBPR);
 510             pr_debug("The TV out mode is HD incompatible. Setting to YPBPR.");
 511         }
 512         reg = __raw_readl(tve.base + tve_regs->tve_com_conf_reg);
 513         reg = (reg & ~TVE_STAND_MASK) | TVE_HD1080I60_STAND;
 514         __raw_writel(reg, tve.base + tve_regs->tve_com_conf_reg);
 515         pr_debug("TVE: change to 1080I60 video\n");
 516     } else if (mode == TVOUT_FMT_1080I50) {
 517         tve_disable_vga_mode();
 518         if (!_is_tvout_mode_hd_compatible()) {
 519             tve_set_tvout_mode(YPBPR);
 520             pr_debug("The TV out mode is HD incompatible. Setting to YPBPR.");
 521         }
 522         reg = __raw_readl(tve.base + tve_regs->tve_com_conf_reg);
 523         reg = (reg & ~TVE_STAND_MASK) | TVE_HD1080I50_STAND;
 524         __raw_writel(reg, tve.base + tve_regs->tve_com_conf_reg);
 525         pr_debug("TVE: change to 1080I50 video\n");
 526     } else if (mode == TVOUT_FMT_1080P30) {
 527         tve_disable_vga_mode();
 528         if (!_is_tvout_mode_hd_compatible()) {
 529             tve_set_tvout_mode(YPBPR);
 530             pr_debug("The TV out mode is HD incompatible. Setting to YPBPR.");
 531         }
 532         reg = __raw_readl(tve.base + tve_regs->tve_com_conf_reg);
 533         reg = (reg & ~TVE_STAND_MASK) | TVE_HD1080P30_STAND;
 534         __raw_writel(reg, tve.base + tve_regs->tve_com_conf_reg);
 535         pr_debug("TVE: change to 1080P30 video\n");
 536     } else if (mode == TVOUT_FMT_1080P25) {
 537         tve_disable_vga_mode();
 538         if (!_is_tvout_mode_hd_compatible()) {
 539             tve_set_tvout_mode(YPBPR);
 540             pr_debug("The TV out mode is HD incompatible. Setting to YPBPR.");
 541         }
 542         reg = __raw_readl(tve.base + tve_regs->tve_com_conf_reg);
 543         reg = (reg & ~TVE_STAND_MASK) | TVE_HD1080P25_STAND;
 544         __raw_writel(reg, tve.base + tve_regs->tve_com_conf_reg);
 545         pr_debug("TVE: change to 1080P25 video\n");
 546     } else if (mode == TVOUT_FMT_1080P24) {
 547         tve_disable_vga_mode();
 548         if (!_is_tvout_mode_hd_compatible()) {
 549             tve_set_tvout_mode(YPBPR);
 550             pr_debug("The TV out mode is HD incompatible. Setting to YPBPR.");
 551         }
 552         reg = __raw_readl(tve.base + tve_regs->tve_com_conf_reg);
 553         reg = (reg & ~TVE_STAND_MASK) | TVE_HD1080P24_STAND;
 554         __raw_writel(reg, tve.base + tve_regs->tve_com_conf_reg);
 555         pr_debug("TVE: change to 1080P24 video\n");
 556     } else if ((mode == TVOUT_FMT_VGA_XGA) || (mode == TVOUT_FMT_VGA_SXGA)) {
 557         /* do not need cable detect */
 558         tve_setup_vga();
 559         pr_debug("TVE: change to VGA video\n");
 560     } else if (mode == TVOUT_FMT_OFF) {
 561         __raw_writel(0x0, tve.base + tve_regs->tve_com_conf_reg);
 562         pr_debug("TVE: change to OFF video\n");
 563     } else {
 564         pr_debug("TVE: no such video format.\n");
 565     }
 566
 567     if (!enabled)
 568         clk_disable(tve.clk);
 569
 570     spin_unlock_irqrestore(&tve_lock, lock_flags);
 571     return 0;
 572 }

428 ~ 454根据输出模式,设置时钟屏率,这里没搞明白这几个时钟的关系,以后再分析
455和465 先关闭再使能,为了保证所有情况下都打开tve.clk,以便下面对tve的操作。

458 ~ 467 设置parent clock, tve clk以及di1 clock的时钟频率

472 ~565 根据mode设置TVE的输出格式,这里没看明白的就是474行,传入的 mode为什么是YPBPR? 不是应该传入CVBS0吗,看不懂,觉得这里有问题,或者这里需要根据情况hard code;然后把输出模式设置到tve_com_conf_reg中

567 ~ 568 已经用完tve.clk,关闭它


 333 static void tve_set_tvout_mode(int mode)
 334 {
 335     u32 conf_reg;
 336
 337     /* clear sync_ch and tvout_mode fields */
 338     conf_reg = __raw_readl(tve.base + tve_regs->tve_com_conf_reg);
 339     conf_reg &= ~(tve_reg_fields->sync_ch_mask |
 340                 tve_reg_fields->tvout_mode_mask);
 341
 342     conf_reg = conf_reg & ~TVE_DAC_SAMPRATE_MASK;
 343     if (tve.revision == 2) {
 344         conf_reg = (conf_reg & ~TVEV2_DATA_SRC_MASK) |
 345             TVEV2_DATA_SRC_BUS_1;
 346         conf_reg = conf_reg & ~TVEV2_INP_VIDEO_FORM;
 347         conf_reg = conf_reg & ~TVEV2_P2I_CONV_EN;
 348     }
 349
 350     conf_reg |=
 351         mode << tve_reg_fields->
 352         tvout_mode_offset | tvout_mode_to_channel_map[mode] <<
 353         tve_reg_fields->sync_ch_offset;
 354     __raw_writel(conf_reg, tve.base + tve_regs->tve_com_conf_reg);
 355 }

344 ~ 345 设置TVEV2_DATA_SRC 为BUS_1,这里还是hard code,其实我觉得也可以设置为BUS_2,那么数据就从IPU data bus2过来

346 设置input video的格式为YCbCr422

347 禁止progressive 到interlace的转换,我觉得如果是要得到NTSC PAL输出,最好使能它

350 ~ 355 根据给定的模式设置TV_OUT_MODE, 以及SYNC_CH_X_EN


小结:

分析后,如果想要实现自己的LCD+cvbs双屏输入,还需要定制一些参数,也许没看懂,做freescale的东西,真累。





你可能感兴趣的:(mx51 TVOUT分析)