/*! * @brief Enable LCD controller. * @param info framebuffer information pointer */ static void _enable_lcdc(struct fb_info *info) { static int first_enable = 1; struct mx2fb_info *mx2fbi = (struct mx2fb_info *)info->par; /* * Graphic window can only be enabled while the HCLK to the LCDC * is disabled. Once enabled it can subsequently be disabled and * enabled without turning off the HCLK. * The graphic window is enabled and then disabled here. So next * time to enable graphic window the HCLK to LCDC does not need * to be disabled, and the flicker (due to disabling of HCLK to * LCDC) is avoided. */ if (first_enable) { _enable_graphic_window(info); _disable_graphic_window(info); first_enable = 0; } if (mx2fbi->type == MX2FB_TYPE_GW) _enable_graphic_window(info); else if (!fb_enabled) { clk_enable(lcdc_clk); gpio_lcdc_active(); board_power_lcd(1); _set_brightness(brightness); fb_enabled++; #ifdef CONFIG_FB_MXC_TVOUT if (fb_mode) { unsigned long mode = 0; if (strcmp(fb_mode, MODE_VGA) == 0) mode = VIDEO_ENCODER_VGA; else if (strcmp(fb_mode, MODE_NTSC) == 0) mode = VIDEO_ENCODER_NTSC; else if (strcmp(fb_mode, MODE_PAL) == 0) mode = VIDEO_ENCODER_PAL; if (mode) fs453_ioctl(ENCODER_SET_NORM, &mode); } #endif } }
/*! * @brief Ioctl function to support customized ioctl operations. * * @param info Framebuffer structure that represents a single frame buffer * @param cmd The command number * @param arg Argument which depends on cmd * * @return Negative errno on error, or zero on success. */ static int mx2fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { struct mx2fb_info *mx2fbi = (struct mx2fb_info *)info->par; struct mx2fb_gbl_alpha ga; struct mx2fb_color_key ck; switch (cmd) { case MX2FB_SET_GBL_ALPHA: if (mx2fbi->type != MX2FB_TYPE_GW) return -ENODEV; if (!arg) return -EINVAL; /* set graphic window information */ if (copy_from_user((void *)&ga, (void *)arg, sizeof(ga))) return -EFAULT; g_gwinfo.alpha_value = ga.alpha; if (g_gwinfo.enabled) _enable_graphic_window(info); else _disable_graphic_window(info); break; case MX2FB_SET_CLR_KEY: if (mx2fbi->type != MX2FB_TYPE_GW) return -ENODEV; if (!arg) return -EINVAL; /* set graphic window information */ if (copy_from_user((void *)&ck, (void *)arg, sizeof(ck))) return -EFAULT; g_gwinfo.ck_enabled = ck.enable; g_gwinfo.ck_red = (ck.color_key & 0x003F0000) >> 16; g_gwinfo.ck_green = (ck.color_key & 0x00003F00) >> 8; g_gwinfo.ck_blue = ck.color_key & 0x0000003F; if (g_gwinfo.enabled) _enable_graphic_window(info); else _disable_graphic_window(info); break; case FBIOGET_GWINFO: if (mx2fbi->type != MX2FB_TYPE_GW) return -ENODEV; if (!arg) return -EINVAL; /* get graphic window information */ if (copy_to_user((void *)arg, (void *)&g_gwinfo, sizeof(g_gwinfo))) return -EFAULT; break; case FBIOPUT_GWINFO: if (mx2fbi->type != MX2FB_TYPE_GW) return -ENODEV; if (!arg) return -EINVAL; /* set graphic window information */ if (copy_from_user((void *)&g_gwinfo, (void *)arg, sizeof(g_gwinfo))) return -EFAULT; if (g_gwinfo.enabled) _enable_graphic_window(info); else _disable_graphic_window(info); break; #ifdef CONFIG_FB_MXC_TVOUT case ENCODER_GET_CAPABILITIES:{ int ret; struct video_encoder_capability cap; if (mx2fbi->type != MX2FB_TYPE_BG) return -ENODEV; ret = fs453_ioctl(cmd, &cap); if (ret) return ret; if (copy_to_user((void *)arg, &cap, sizeof(cap))) return -EFAULT; break; } case ENCODER_SET_NORM:{ int ret; unsigned long mode; char *smode; struct fb_var_screeninfo var; if (mx2fbi->type != MX2FB_TYPE_BG) return -ENODEV; if (copy_from_user(&mode, (void *)arg, sizeof(mode))) return -EFAULT; if ((ret = fs453_ioctl(cmd, &mode))) return ret; if (mode == VIDEO_ENCODER_PAL) smode = MODE_PAL; else if (mode == VIDEO_ENCODER_NTSC) smode = MODE_NTSC; else smode = MODE_VGA; var = info->var; var.nonstd = 0; ret = fb_find_mode(&var, info, smode, mxcfb_modedb, mxcfb_modedb_sz, NULL, default_bpp); if ((ret != 1) && (ret != 2)) /* specified mode not found */ return -ENODEV; info->var = var; fb_mode = smode; return mx2fb_set_par(info); } case ENCODER_SET_INPUT: case ENCODER_SET_OUTPUT: case ENCODER_ENABLE_OUTPUT:{ unsigned long varg; if (mx2fbi->type != MX2FB_TYPE_BG) return -ENODEV; if (copy_from_user(&varg, (void *)arg, sizeof(varg))) return -EFAULT; return fs453_ioctl(cmd, &varg); } #endif default: dev_dbg(info->device, "Unknown ioctl command (0x%08X)\n", cmd); return -EINVAL; } return 0; }
/*! * @brief Update LCDC registers * @param info framebuffer information pointer */ static void _update_lcdc(struct fb_info *info) { unsigned long base; unsigned long perclk3, pcd, pcr; struct fb_var_screeninfo *var = &info->var; struct mx2fb_info *mx2fbi = (struct mx2fb_info *)info->par; if (mx2fbi->type == MX2FB_TYPE_GW) { _enable_graphic_window(info); return; } base = (var->yoffset * var->xres_virtual + var->xoffset); base *= (var->bits_per_pixel) / 8; base += info->fix.smem_start; /* Screen start address register */ __raw_writel(base, LCDC_REG(LCDC_LSSAR)); /* Size register */ dev_dbg(info->device, "xres = %d, yres = %d\n", info->var.xres, info->var.yres); __raw_writel(((info->var.xres >> 4) << 20) + info->var.yres, LCDC_REG(LCDC_LSR)); /* Virtual page width register */ __raw_writel(info->var.xres_virtual >> 1, LCDC_REG(LCDC_LVPWR)); /* To setup LCDC pixel clock */ perclk3 = clk_round_rate(lcdc_clk, 134000000); if (clk_set_rate(lcdc_clk, perclk3)) { printk(KERN_INFO "mx2fb: Unable to set clock to %lu\n", perclk3); perclk3 = clk_get_rate(lcdc_clk); } /* Calculate pixel clock divider, and round to the nearest integer */ pcd = (perclk3 * 8 / (PICOS2KHZ(var->pixclock) * 1000UL) + 4) / 8; if (--pcd > 0x3F) pcd = 0x3F; /* Panel configuration register */ pcr = 0xFA008B80 | pcd; pcr |= (var->sync & FB_SYNC_CLK_INVERT) ? 0x01000000 : 0; pcr |= (var->sync & FB_SYNC_SHARP_MODE) ? 0x00000040 : 0; pcr |= (var->sync & FB_SYNC_OE_ACT_HIGH) ? 0 : 0x00100000; __raw_writel(pcr, LCDC_REG(LCDC_LPCR)); /* Horizontal and vertical configuration register */ __raw_writel(((var->hsync_len - 1) << 26) + ((var->right_margin - 1) << 8) + (var->left_margin - 3), LCDC_REG(LCDC_LHCR)); __raw_writel((var->vsync_len << 26) + (var->lower_margin << 8) + var->upper_margin, LCDC_REG(LCDC_LVCR)); /* Sharp configuration register */ __raw_writel(0x00120300, LCDC_REG(LCDC_LSCR)); /* Refresh mode control reigster */ __raw_writel(0x00000000, LCDC_REG(LCDC_LRMCR)); /* DMA control register */ if (cpu_is_mx27_rev(CHIP_REV_2_0) > 0) __raw_writel(0x00040060, LCDC_REG(LCDC_LDCR)); else __raw_writel(0x00020010, LCDC_REG(LCDC_LDCR)); }