现在的位置: 首页 > 综合 > 正文

mx51 TVOUT分析

2012年01月28日 ⁄ 综合 ⁄ 共 10067字 ⁄ 字号 评论关闭

转: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);

抱歉!评论已关闭.