接上文,看完了结构体,也也应该知道个大概了,整个驱动部分围绕fb_info来,对其进行填充最后调用frambuffer_register将其注册进内核,
接下来看详细分析:
426 static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
427 {
428 int retval = 0;
429 int __user *argp = (void __user *)arg;
430
431 if ((retval = wait_event_interruptible(mxcfb_drv_data.suspend_wq,
432 (mxcfb_drv_data.suspended ==
433 false))) < 0) {
434 return retval;
435 }
436
437 switch (cmd) {
438 case MXCFB_SET_GBL_ALPHA:
439 {
440 struct mxcfb_gbl_alpha ga;
441 if (copy_from_user(&ga, (void *)arg, sizeof(ga))) {
) {
442 retval = -EFAULT;
443 break;
444 }
445 retval =
446 ipu_sdc_set_global_alpha((bool) ga.enable,
447 ga.alpha);
448 dev_dbg(fbi->device, "Set global alpha to %d\n",
449 ga.alpha);
450 break;
451 }
452 case MXCFB_SET_CLR_KEY:
453 {
454 struct mxcfb_color_key key;
455 if (copy_from_user(&key, (void *)arg, sizeof(key))) {
456 retval = -EFAULT;
457 break;
458 }
459 retval = ipu_sdc_set_color_key(MEM_SDC_BG, key.enable,
nable,
460 key.color_key);
461 dev_dbg(fbi->device, "Set color key to 0x%08X\n",
462 key.color_key);
463 break;
464 }
465 case MXCFB_WAIT_FOR_VSYNC:
466 {
467 #ifndef CONFIG_ARCH_MX3
468 mxcfb_drv_data.vsync_flag = 0;
469 ipu_enable_irq(IPU_IRQ_SDC_DISP3_VSYNC);
470 if (!wait_event_interruptible_timeout
471 (mxcfb_drv_data.vsync_wq,
472 mxcfb_drv_data.vsync_flag != 0, 1 * HZ)) {
473 dev_err(fbi->device,
474 "MXCFB_WAIT_FOR_VSYNC: timeout\n");
475 retval = -ETIME;
476 break;
477 } else if (signal_pending(current)) {
478 dev_err(fbi->device,
479 "MXCFB_WAIT_FOR_VSYNC: interrupt received\n");
480 retval = -ERESTARTSYS;
481 break;
482 }
483 #endif
484 break;
485 }
486 case MXCFB_GET_FB_IPU_CHAN:
487 {
488 struct mxcfb_info *mxc_fbi =
489 (struct mxcfb_info *)fbi->par;
490
491 if (put_user(mxc_fbi->ipu_ch, argp))
492 return -EFAULT;
493
494 break;
495 }
496 default:
497 retval = -EINVAL;
498 }
499 return retval;
500 }
826 static struct fb_ops mxcfb_ops = {
827 .owner = THIS_MODULE,
828 .fb_set_par = mxcfb_set_par,
829 .fb_check_var = mxcfb_check_var,
830 .fb_setcolreg = mxcfb_setcolreg,
831 .fb_pan_display = mxcfb_pan_display,
832 .fb_ioctl = mxcfb_ioctl,
833 .fb_fillrect = cfb_fillrect,
834 .fb_copyarea = cfb_copyarea,
835 .fb_imageblit = cfb_imageblit,
836 .fb_blank = mxcfb_blank,
837 };
838
- struct fb_info *framebuffer_alloc(size_t size, struct device *dev)
- {
- #define BYTES_PER_LONG (BITS_PER_LONG/8)
- #define PADDING (BYTES_PER_LONG - (sizeof(struct fb_info) % BYTES_PER_LONG))
- int fb_info_size = sizeof(struct fb_info);
- struct fb_info *info;
- char *p;
- if (size)
- fb_info_size += PADDING;
- p = kzalloc(fb_info_size + size, GFP_KERNEL);
- if (!p)
- return NULL;
- info = (struct fb_info *) p;
- if (size)
- info->par = p + fb_info_size;
- info->device = dev;
- #ifdef CONFIG_FB_BACKLIGHT
- mutex_init(&info->bl_curve_mutex);
- #endif
- return info;
- #undef PADDING
- #undef BYTES_PER_LONG
- }
125 static int mxcfb_set_fix(struct fb_info *info)
126 {
127 struct fb_fix_screeninfo *fix = &info->fix;
128 struct fb_var_screeninfo *var = &info->var;
129 struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)info->par;
130
131 if (mxc_fbi->ipu_ch == MEM_SDC_FG)
132 strncpy(fix->id, "DISP3 FG", 8);
133 else
134 strncpy(fix->id, "DISP3 BG", 8);
135
136 fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
137
138 fix->type = FB_TYPE_PACKED_PIXELS;
139 fix->accel = FB_ACCEL_NONE;
140 fix->visual = FB_VISUAL_TRUECOLOR;
141 fix->xpanstep = 1;
142 fix->ypanstep = 1;
143
144 return 0;
145 }
146
973 /*
974 * Main framebuffer functions
975 */
976
977 /*!
978 * Allocates the DRAM memory for the frame buffer. This buffer is remapped
979 * into a non-cached, non-buffered, memory region to allow palette and pixel
980 * writes to occur without flushing the cache. Once this area is remapped,
981 * all virtual memory access to the video memory should occur at the new region.
982 *
983 * @param fbi framebuffer information pointer
984 *
985 * @param use_internal_ram flag on whether to use internal RAM for memory
986 *
987 * @return Error code indicating success or failure
988 */
989 static int mxcfb_map_video_memory(struct fb_info *fbi, bool use_internal_ram)
990 {
991 int retval = 0;
992
993 #ifdef CONFIG_FB_MXC_INTERNAL_MEM
994 if (use_internal_ram) {
995 fbi->fix.smem_len = FB_RAM_SIZE;
996 fbi->fix.smem_start = FB_RAM_BASE_ADDR;
997 if (fbi->fix.smem_len <
998 (fbi->var.yres_virtual * fbi->fix.line_length)) {
999 dev_err(fbi->device,
1000 "Not enough internal RAM for framebuffer configuration\n");
1001 retval = -EINVAL;
1002 goto err0;
1003 }
1004
1005 if (request_mem_region(fbi->fix.smem_start, fbi->fix.smem_len,
1006 fbi->device->driver->name) == NULL) {
L) {
1007 dev_err(fbi->device,
1008 "Unable to request internal RAM\n");
1009 retval = -ENOMEM;
1010 goto err0;
1011 }
1012
1013 if (!(fbi->screen_base = ioremap(fbi->fix.smem_start,
1014 fbi->fix.smem_len))) {
1015 dev_err(fbi->device,
1016 "Unable to map fb memory to virtual address\n");
1017 release_mem_region(fbi->fix.smem_start,
1018 fbi->fix.smem_len);
1019 retval = -EIO;
1020 goto err0;
1021 }
1022
1023 iram_clk = clk_get(NULL, "iram_clk");
1024 clk_enable(iram_clk);
1025 } else
1026 #endif
1027 {
1028 fbi->fix.smem_len = fbi->var.yres_virtual *
1029 fbi->fix.line_length;
1030 fbi->screen_base =
1031 dma_alloc_writecombine(fbi->device,
1032 fbi->fix.smem_len,
1033 (dma_addr_t *) & fbi->fix.smem_start,
1034 GFP_DMA);
1035
1036 if (fbi->screen_base == 0) {
1037 dev_err(fbi->device,
1038 "Unable to allocate framebuffer memory\n");
1039 retval = -EBUSY;
1040 goto err0;
1041 }
1042 }
1043
1044 dev_dbg(fbi->device, "allocated fb @ paddr=0x%08X, size=%d.\n",
1045 (uint32_t) fbi->fix.smem_start, fbi->fix.smem_len);
1046
1047 fbi->screen_size = fbi->fix.smem_len;
1048
1049 /* Clear the screen */
1050 memset((char *)fbi->screen_base, 0, fbi->fix.smem_len);
1051
1052 return 0;
1053
1054 err0:
1055 fbi->fix.smem_len = 0;
1056 fbi->fix.smem_start = 0;
1057 fbi->screen_base = NULL;
1058 return retval;
1059 }
147 /*
148 * Set framebuffer parameters and change the operating mode.
149 *
150 * @param info framebuffer information pointer
151 */
152 static int mxcfb_set_par(struct fb_info *fbi)
153 {
154 int retval;
155 bool use_iram = false;
156 u32 mem_len;
157 ipu_di_signal_cfg_t sig_cfg;
158 ipu_panel_t mode = IPU_PANEL_TFT;
159 struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
160
161 if ((retval = wait_event_interruptible(mxcfb_drv_data.suspend_wq,
162 (mxcfb_drv_data.suspended ==
163 false))) < 0) {
164 return retval;
165 }
166
167 ipu_disable_irq(mxc_fbi->ipu_ch_irq);
168 ipu_disable_channel(mxc_fbi->ipu_ch, true);
169 ipu_uninit_channel(mxc_fbi->ipu_ch);
170 ipu_clear_irq(mxc_fbi->ipu_ch_irq);
171 mxcfb_set_fix(fbi);
//初始化fbi->fix变量
172
173 mem_len = fbi->var.yres_virtual * fbi->fix.line_length;
//计算显存的大小,根据fbi->var.xres_virtual *fbi->var,bits_per_pixal / 8 * fbi->var.yres_virtual;
174 if (mem_len > fbi->fix.smem_len) {
175 if (fbi->fix.smem_start)
176 mxcfb_unmap_video_memory(fbi);
177
178 #ifdef CONFIG_FB_MXC_INTERNAL_MEM
179 if (mxc_fbi->ipu_ch == MEM_SDC_BG) {
180 use_iram = true;
181 }
182 #endif
183 if (mxcfb_map_video_memory(fbi, use_iram) < 0)
184 return -ENOMEM;
185 }
186
187 ipu_init_channel(mxc_fbi->ipu_ch, NULL);
188
189 /* Clear the screen */
190 memset((char *)fbi->screen_base, 0, fbi->fix.smem_len);
191
191
192 if (mxc_fbi->ipu_ch == MEM_SDC_BG) {
193 memset(&sig_cfg, 0, sizeof(sig_cfg));
194 if (fbi->var.sync & FB_SYNC_HOR_HIGH_ACT)
195 sig_cfg.Hsync_pol = true;
196 if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT)
197 sig_cfg.Vsync_pol = true;
198 if (!(fbi->var.sync & FB_SYNC_CLK_LAT_FALL))
199 sig_cfg.clk_pol = true;
200 if (fbi->var.sync & FB_SYNC_DATA_INVERT)
201 sig_cfg.data_pol = true;
202 if (!(fbi->var.sync & FB_SYNC_OE_LOW_ACT))
203 sig_cfg.enable_pol = true;
204 if (fbi->var.sync & FB_SYNC_CLK_IDLE_EN)
205 sig_cfg.clkidle_en = true;
206 if (fbi->var.sync & FB_SYNC_SHARP_MODE)
207 mode = IPU_PANEL_SHARP_TFT;
208
209 dev_dbg(fbi->device, "pixclock = %ul Hz\n",
210 (u32) (PICOS2KHZ(fbi->var.pixclock) * 1000UL));
211
212 if (ipu_sdc_init_panel(mode,
213 (PICOS2KHZ(fbi->var.pixclock)) * 1000UL,
214 fbi->var.xres, fbi->var.yres,
215 (fbi->var.sync & FB_SYNC_SWAP_RGB) ?
216 IPU_PIX_FMT_BGR666 : IPU_PIX_FMT_RGB666,
217 fbi->var.left_margin,
218 fbi->var.hsync_len,
219 fbi->var.right_margin,
220 fbi->var.upper_margin,
221 fbi->var.vsync_len,
222 fbi->var.lower_margin, sig_cfg) != 0) {
223 dev_err(fbi->device,
224 "mxcfb: Error initializing panel.\n");
225 return -EINVAL;
226 }
227
228 fbi->mode =
229 (struct fb_videomode *)fb_match_mode(&fbi->var,
230 &fbi->modelist);
231 }
232
233 ipu_disp_set_window_pos(mxc_fbi->ipu_ch, 0, 0);
234
235 mxc_fbi->cur_ipu_buf = 1;
236 sema_init(&mxc_fbi->flip_sem, 1);
237 fbi->var.xoffset = fbi->var.yoffset = 0;
238
239 retval = ipu_init_channel_buffer(mxc_fbi->ipu_ch, IPU_INPUT_BUFFER,
240 bpp_to_pixfmt(fbi->var.bits_per_pixel),
241 fbi->var.xres, fbi->var.yres,
242 fbi->var.xres_virtual,
243 IPU_ROTATE_NONE,
244 fbi->fix.smem_start +
245 (fbi->fix.line_length * fbi->var.yres),
246 fbi->fix.smem_start,
247 0, 0);
248 if (retval) {
249 dev_err(fbi->device,
250 "ipu_init_channel_buffer error %d\n", retval);
251 return retval;
252 }
253
254 if (mxc_fbi->blank == FB_BLANK_UNBLANK) {
255 ipu_enable_channel(mxc_fbi->ipu_ch);
256 }
257
258 return 0;
259 }
1098 static struct fb_info *mxcfb_init_fbinfo(struct device *dev, struct fb_ops *ops)
1099 {
1100 struct fb_info *fbi;
1101 struct mxcfb_info *mxcfbi;
1102
1103 /*
1104 * Allocate sufficient memory for the fb structure
1105 */
1106 fbi = framebuffer_alloc(sizeof(struct mxcfb_info), dev);
// 申请struct fb_info + struct mxcfb_info
1107 if (!fbi)
1108 return NULL;
1109
1110 mxcfbi = (struct mxcfb_info *)fbi->par;
1111
1112 fbi->var.activate = FB_ACTIVATE_NOW;
1113
1114 fbi->fbops = ops;
1115 fbi->flags = FBINFO_FLAG_DEFAULT;
1116 fbi->pseudo_palette = mxcfbi->pseudo_palette;
//指定fbi的调色板为fbi->par->pseudo_palette;
1117
1118 spin_lock_init(&mxcfbi->fb_lock);
1119
1120 /*
1121 * Allocate colormap
1122 */
1123 fb_alloc_cmap(&fbi->cmap, 16, 0);
//分配颜色位图
1124
1125 return fbi;
1126 }
612 /*
613 * mxcfb_blank():
614 * Blank the display.
615 */
616 static int mxcfb_blank(int blank, struct fb_info *info)
617 {
618 int retval;
619 struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)info->par;
620
621 dev_dbg(info->device, "blank = %d\n", blank);
622
623 if (mxc_fbi->blank == blank)
624 return 0;
625
626 if ((retval = wait_event_interruptible(mxcfb_drv_data.suspend_wq,
627 (mxcfb_drv_data.suspended ==
628 false))) < 0) {
629 return retval;
630 }
631
632 mxc_fbi->blank = blank;
633
634 switch (blank) {
635 case FB_BLANK_POWERDOWN:
636 case FB_BLANK_VSYNC_SUSPEND:
637 case FB_BLANK_HSYNC_SUSPEND:
638 case FB_BLANK_NORMAL:
639 ipu_disable_channel(MEM_SDC_BG, true);
640 gpio_lcd_inactive();
641 break;
642 case FB_BLANK_UNBLANK:
643 gpio_lcd_active();
644 ipu_enable_channel(MEM_SDC_BG);
645 break;
646 }
647 return 0;
648 }
static int mxcfb_probe(struct platform_device *pdev)
1137 {
1138 char *mode = pdev->dev.platform_data;
1139 struct fb_info *fbi;
1140 struct mxcfb_info *mxcfbi;
1141 struct fb_info *fbi_ovl;
1142 int ret = 0;
1143
1144 /*
1145 * Initialize FB structures
1146 */
1147 fbi = mxcfb_init_fbinfo(&pdev->dev, &mxcfb_ops);
// 此函数申请了一个结构为struct fb_info的fbi,设置fbi的成员pseudo_palette(调色板)
//设置fbi成员var.avtive=FB_ACTIVATE_NOW;设置fbi的flag=FBINFO_FLAG_DEFAULT;
//设置fbi的ops,初始化颜色分量(要好好分析)
1148 if (!fbi) {
1149 ret = -ENOMEM;
1150 goto err0;
1151 }
1152 mxcfbi = (struct mxcfb_info *)fbi->par;
1153
1154 mxcfbi->ipu_ch_irq = IPU_IRQ_SDC_BG_EOF;
1155 mxcfbi->cur_ipu_buf = 0;
1156 mxcfbi->ipu_ch = MEM_SDC_BG;
1157
1158 ipu_sdc_set_global_alpha(true, 0xFF);
1159 ipu_sdc_set_color_key(MEM_SDC_BG, false, 0);
1160
1161 if (ipu_request_irq(IPU_IRQ_SDC_BG_EOF, mxcfb_irq_handler, 0,
1162 MXCFB_NAME, fbi) != 0) {
1163 dev_err(&pdev->dev, "Error registering BG irq handler.\n");
1164 ret = -EBUSY;
1165 goto err1;
1166 }
1167 ipu_disable_irq(IPU_IRQ_SDC_BG_EOF);
1168
1169 if (fb_mode == NULL) {
1170 fb_mode = mode;
1171 }
1172
1173 if (!fb_find_mode(&fbi->var, fbi, fb_mode, mxcfb_modedb,
1174 mxcfb_modedb_sz, NULL, default_bpp)) {
1175 ret = -EBUSY;
1176 goto err2;
1177 }
//fb_find_mode从mxcfb_modedb(struct fb_videomode)中根据fb_mode值找出对于自己的那块屏的参数
//然后初始化fbi->var
1178 fb_videomode_to_modelist(mxcfb_modedb, mxcfb_modedb_sz, &fbi->modelist);
//将好几块屏的mode添加到链表里,不知道何用
1179
1180 /* Default Y virtual size is 2x panel size */
1181 #ifndef CONFIG_FB_MXC_INTERNAL_MEM
1182 fbi->var.yres_virtual = fbi->var.yres * 2;
1183 #endif
1184
1185 mxcfb_drv_data.fbi = fbi;
1186 mxcfb_drv_data.backlight_level = 255;
1187 mxcfb_drv_data.suspended = false;
1188 init_waitqueue_head(&mxcfb_drv_data.suspend_wq);
1189
1190 mxcfbi->blank = FB_BLANK_NORMAL;
1191 ret = mxcfb_set_par(fbi);
//初始化fbi->fix 以及显存
1192 if (ret < 0) {
1193 goto err2;
1194 }
1195 mxcfb_blank(FB_BLANK_UNBLANK, fbi);
1196
1197 /*
1198 * Register framebuffer
1199 */
1200 ret = register_framebuffer(fbi);
1201 if (ret < 0) {
1202 goto err2;
1203 }
1204
1205 /*
1206 * Initialize Overlay FB structures
1207 */
1208 fbi_ovl = mxcfb_init_fbinfo(&pdev->dev, &mxcfb_ovl_ops);
1209 if (!fbi_ovl) {
1210 ret = -ENOMEM;
1211 goto err3;
1212 }
1213 mxcfb_drv_data.fbi_ovl = fbi_ovl;
1214 mxcfbi = (struct mxcfb_info *)fbi_ovl->par;
1216 mxcfbi->ipu_ch_irq = IPU_IRQ_SDC_FG_EOF;
1217 mxcfbi->cur_ipu_buf = 0;
1218 mxcfbi->ipu_ch = MEM_SDC_FG;
1219
1220 if (ipu_request_irq(IPU_IRQ_SDC_FG_EOF, mxcfb_irq_handler, 0,
1221 MXCFB_NAME, fbi_ovl) != 0) {
1222 dev_err(fbi->device, "Error registering FG irq handler.\n");
1223 ret = -EBUSY;
1224 goto err4;
1225 }
1226 ipu_disable_irq(mxcfbi->ipu_ch_irq);
1227
1228 /* Default Y virtual size is 2x panel size */
1229 fbi_ovl->var = fbi->var;
1230 fbi_ovl->var.yres_virtual = fbi->var.yres * 2;
1231
1232 /* Overlay is blanked by default */
1233 mxcfbi->blank = FB_BLANK_NORMAL;
1234
1235 ret = mxcfb_set_par(fbi_ovl);
1236 if (ret < 0) {
1237 goto err5;
1238 }
1239
1240 /*
1241 * Register overlay framebuffer
1242 */
1243 ret = register_framebuffer(fbi_ovl);
1244 if (ret < 0) {
1245 goto err5;
1246 }
1247
1248 platform_set_drvdata(pdev, &mxcfb_drv_data);
1249
1250 init_waitqueue_head(&mxcfb_drv_data.vsync_wq);
1251 if (!cpu_is_mx31() && !cpu_is_mx32()) {
1252 if ((ret = ipu_request_irq(IPU_IRQ_SDC_DISP3_VSYNC,
1253 mxcfb_vsync_irq_handler,
1254 0, MXCFB_NAME,
1255 &mxcfb_drv_data)) < 0) {
1256 goto err6;
1257 }
1258 ipu_disable_irq(IPU_IRQ_SDC_DISP3_VSYNC);
1259 }
1260
1261 printk(KERN_INFO "mxcfb: fb registered, using mode %s\n", fb_mode);
1262 return 0;
1263
1264 err6:
1265 unregister_framebuffer(fbi_ovl);
1266 err5:
1267 ipu_free_irq(IPU_IRQ_SDC_FG_EOF, fbi_ovl);
1268 err4:
1269 fb_dealloc_cmap(&fbi_ovl->cmap);
1270 framebuffer_release(fbi_ovl);
1271 err3:
1272 unregister_framebuffer(fbi);
1273 err2:
1274 ipu_free_irq(IPU_IRQ_SDC_BG_EOF, fbi);
1275 err1:
1276 fb_dealloc_cmap(&fbi->cmap);
1277 framebuffer_release(fbi);
1278 err0:
1279 printk(KERN_ERR "mxcfb: failed to register fb\n");
1280 return ret;
1281 }
1282
1215