转:http://blog.csdn.net/kickxxx/article/details/6777980
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);