// SPDX-License-Identifier: GPL-2.0-only/* * Freescale i.MX Frame Buffer device driver * * Copyright (C) 2004 Sascha Hauer, Pengutronix * Based on acornfb.c Copyright (C) Russell King. * * Please direct your questions and comments on this driver to the following * email address: * * linux-arm-kernel@lists.arm.linux.org.uk */ #include <linux/module.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/interrupt.h>#include <linux/slab.h>#include <linux/mm.h>#include <linux/fb.h>#include <linux/delay.h>#include <linux/init.h>#include <linux/ioport.h>#include <linux/cpufreq.h>#include <linux/clk.h>#include <linux/platform_device.h>#include <linux/dma-mapping.h>#include <linux/io.h>#include <linux/lcd.h>#include <linux/math64.h>#include <linux/of.h>#include <linux/bitfield.h> #include <linux/regulator/consumer.h> #include <video/of_display_timing.h>#include <video/of_videomode.h>#include <video/videomode.h> struct imx_fb_videomode { struct fb_videomode mode; u32 pcr; bool aus_mode; unsigned char bpp;}; /* * Complain if VAR is out of range. */#define DEBUG_VAR 1 #define DRIVER_NAME "imx-fb" #define LCDC_SSA 0x00 #define LCDC_SIZE 0x04#define SIZE_XMAX_MASK GENMASK(25, 20) #define YMAX_MASK_IMX1 GENMASK(8, 0)#define YMAX_MASK_IMX21 GENMASK(9, 0) #define LCDC_VPW 0x08#define VPW_VPW_MASK GENMASK(9, 0) #define LCDC_CPOS 0x0C#define CPOS_CC1 BIT(31)#define CPOS_CC0 BIT(30)#define CPOS_OP BIT(28)#define CPOS_CXP_MASK GENMASK(25, 16) #define LCDC_LCWHB 0x10#define LCWHB_BK_EN BIT(31)#define LCWHB_CW_MASK GENMASK(28, 24)#define LCWHB_CH_MASK GENMASK(20, 16)#define LCWHB_BD_MASK GENMASK(7, 0) #define LCDC_LCHCC 0x14 #define LCDC_PCR 0x18#define PCR_TFT BIT(31)#define PCR_COLOR BIT(30)#define PCR_BPIX_MASK GENMASK(27, 25)#define PCR_BPIX_8 3#define PCR_BPIX_12 4#define PCR_BPIX_16 5#define PCR_BPIX_18 6#define PCR_PCD_MASK GENMASK(5, 0) #define LCDC_HCR 0x1C#define HCR_H_WIDTH_MASK GENMASK(31, 26)#define HCR_H_WAIT_1_MASK GENMASK(15, 8)#define HCR_H_WAIT_2_MASK GENMASK(7, 0) #define LCDC_VCR 0x20#define VCR_V_WIDTH_MASK GENMASK(31, 26)#define VCR_V_WAIT_1_MASK GENMASK(15, 8)#define VCR_V_WAIT_2_MASK GENMASK(7, 0) #define LCDC_POS 0x24#define POS_POS_MASK GENMASK(4, 0) #define LCDC_LSCR1 0x28/* bit fields in imxfb.h */ #define LCDC_PWMR 0x2C/* bit fields in imxfb.h */ #define LCDC_DMACR 0x30/* bit fields in imxfb.h */ #define LCDC_RMCR 0x34 #define RMCR_LCDC_EN_MX1 BIT(1) #define RMCR_SELF_REF BIT(0) #define LCDC_LCDICR 0x38#define LCDICR_INT_SYN BIT(2)#define LCDICR_INT_CON BIT(0) #define LCDC_LCDISR 0x40#define LCDISR_UDR_ERR BIT(3)#define LCDISR_ERR_RES BIT(2)#define LCDISR_EOF BIT(1)#define LCDISR_BOF BIT(0) #define IMXFB_LSCR1_DEFAULT 0x00120300 #define LCDC_LAUSCR 0x80#define LAUSCR_AUS_MODE BIT(31) /* Used fb-mode. Can be set on kernel command line, therefore file-static. */static const char *fb_mode; /* * These are the bitfields for each * display depth that we support. */struct imxfb_rgb { struct fb_bitfield red; struct fb_bitfield green; struct fb_bitfield blue; struct fb_bitfield transp;}; enum imxfb_type { IMX1_FB, IMX21_FB,}; enum imxfb_panel_type { PANEL_TYPE_MONOCHROME, PANEL_TYPE_CSTN, PANEL_TYPE_TFT,}; struct imxfb_info { struct platform_device *pdev; void __iomem *regs; struct clk *clk_ipg; struct clk *clk_ahb; struct clk *clk_per; enum imxfb_type devtype; enum imxfb_panel_type panel_type; bool enabled; /* * These are the addresses we mapped * the framebuffer memory region to. */ dma_addr_t map_dma; u_int map_size; u_int palette_size; dma_addr_t dbar1; dma_addr_t dbar2; u_int pcr; u_int lauscr; u_int pwmr; u_int lscr1; u_int dmacr; bool cmap_inverse; bool cmap_static; struct imx_fb_videomode *mode; int num_modes; struct regulator *lcd_pwr; int lcd_pwr_enabled;}; static const struct platform_device_id imxfb_devtype[] = { { .name = "imx1-fb", .driver_data = IMX1_FB, }, { .name = "imx21-fb", .driver_data = IMX21_FB, }, { /* sentinel */ }};MODULE_DEVICE_TABLE(platform, imxfb_devtype); static const struct of_device_id imxfb_of_dev_id[] = { { .compatible = "fsl,imx1-fb", .data = &imxfb_devtype[IMX1_FB], }, { .compatible = "fsl,imx21-fb", .data = &imxfb_devtype[IMX21_FB], }, { /* sentinel */ }};MODULE_DEVICE_TABLE(of, imxfb_of_dev_id); static inline int is_imx1_fb(struct imxfb_info *fbi){ return fbi->devtype == IMX1_FB;} #define IMX_NAME "IMX" /* * Minimum X and Y resolutions */#define MIN_XRES 64#define MIN_YRES 64 /* Actually this really is 18bit support, the lowest 2 bits of each colour * are unused in hardware. We claim to have 24bit support to make software * like X work, which does not support 18bit. */static struct imxfb_rgb def_rgb_18 = { .red = {.offset = 16, .length = 8,}, .green = {.offset = 8, .length = 8,}, .blue = {.offset = 0, .length = 8,}, .transp = {.offset = 0, .length = 0,},}; static struct imxfb_rgb def_rgb_16_tft = { .red = {.offset = 11, .length = 5,}, .green = {.offset = 5, .length = 6,}, .blue = {.offset = 0, .length = 5,}, .transp = {.offset = 0, .length = 0,},}; static struct imxfb_rgb def_rgb_16_stn = { .red = {.offset = 8, .length = 4,}, .green = {.offset = 4, .length = 4,}, .blue = {.offset = 0, .length = 4,}, .transp = {.offset = 0, .length = 0,},}; static struct imxfb_rgb def_rgb_8 = { .red = {.offset = 0, .length = 8,}, .green = {.offset = 0, .length = 8,}, .blue = {.offset = 0, .length = 8,}, .transp = {.offset = 0, .length = 0,},}; static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *info); static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf){ chan &= 0xffff; chan >>= 16 - bf->length; return chan << bf->offset;} static int imxfb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue, u_int trans, struct fb_info *info){ struct imxfb_info *fbi = info->par; u_int val, ret = 1; #define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16) if (regno < fbi->palette_size) { val = (CNVT_TOHW(red, 4) << 8) | (CNVT_TOHW(green, 4) << 4) | CNVT_TOHW(blue, 4); writel(val, fbi->regs + 0x800 + (regno << 2)); ret = 0; } return ret;} static int imxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int trans, struct fb_info *info){ struct imxfb_info *fbi = info->par; unsigned int val; int ret = 1; /* * If inverse mode was selected, invert all the colours * rather than the register number. The register number * is what you poke into the framebuffer to produce the * colour you requested. */ if (fbi->cmap_inverse) { red = 0xffff - red; green = 0xffff - green; blue = 0xffff - blue; } /* * If greyscale is true, then we convert the RGB value * to greyscale no mater what visual we are using. */ if (info->var.grayscale) red = green = blue = (19595 * red + 38470 * green + 7471 * blue) >> 16; switch (info->fix.visual) { case FB_VISUAL_TRUECOLOR: /* * 12 or 16-bit True Colour. We encode the RGB value * according to the RGB bitfield information. */ if (regno < 16) { u32 *pal = info->pseudo_palette; val = chan_to_field(red, &info->var.red); val |= chan_to_field(green, &info->var.green); val |= chan_to_field(blue, &info->var.blue); pal[regno] = val; ret = 0; } break; case FB_VISUAL_STATIC_PSEUDOCOLOR: case FB_VISUAL_PSEUDOCOLOR: ret = imxfb_setpalettereg(regno, red, green, blue, trans, info); break; } return ret;} static const struct imx_fb_videomode *imxfb_find_mode(struct imxfb_info *fbi){ struct imx_fb_videomode *m; int i; if (!fb_mode) return &fbi->mode[0]; for (i = 0, m = &fbi->mode[0]; i < fbi->num_modes; i++, m++) { if (!strcmp(m->mode.name, fb_mode)) return m; } return NULL;} /* * imxfb_check_var(): * Round up in the following order: bits_per_pixel, xres, * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale, * bitfields, horizontal timing, vertical timing. */static int imxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info){ struct imxfb_info *fbi = info->par; struct imxfb_rgb *rgb; const struct imx_fb_videomode *imxfb_mode; unsigned long lcd_clk; unsigned long long tmp; u32 pcr = 0; if (var->xres < MIN_XRES) var->xres = MIN_XRES; if (var->yres < MIN_YRES) var->yres = MIN_YRES; imxfb_mode = imxfb_find_mode(fbi); if (!imxfb_mode) return -EINVAL; var->xres = imxfb_mode->mode.xres; var->yres = imxfb_mode->mode.yres; var->bits_per_pixel = imxfb_mode->bpp; var->pixclock = imxfb_mode->mode.pixclock; var->hsync_len = imxfb_mode->mode.hsync_len; var->left_margin = imxfb_mode->mode.left_margin; var->right_margin = imxfb_mode->mode.right_margin; var->vsync_len = imxfb_mode->mode.vsync_len; var->upper_margin = imxfb_mode->mode.upper_margin; var->lower_margin = imxfb_mode->mode.lower_margin; var->sync = imxfb_mode->mode.sync; var->xres_virtual = max(var->xres_virtual, var->xres); var->yres_virtual = max(var->yres_virtual, var->yres); pr_debug("var->bits_per_pixel=%d\n", var->bits_per_pixel); lcd_clk = clk_get_rate(fbi->clk_per); tmp = var->pixclock * (unsigned long long)lcd_clk; do_div(tmp, 1000000); if (do_div(tmp, 1000000) > 500000) tmp++; pcr = (unsigned int)tmp; if (--pcr > PCR_PCD_MASK) { pcr = PCR_PCD_MASK; dev_warn(&fbi->pdev->dev, "Must limit pixel clock to %luHz\n", lcd_clk / pcr); } switch (var->bits_per_pixel) { case 32: pcr |= FIELD_PREP(PCR_BPIX_MASK, PCR_BPIX_18); rgb = &def_rgb_18; break; case 16: default: if (is_imx1_fb(fbi)) pcr |= FIELD_PREP(PCR_BPIX_MASK, PCR_BPIX_12); else pcr |= FIELD_PREP(PCR_BPIX_MASK, PCR_BPIX_16); if (imxfb_mode->pcr & PCR_TFT) rgb = &def_rgb_16_tft; else rgb = &def_rgb_16_stn; break; case 8: pcr |= FIELD_PREP(PCR_BPIX_MASK, PCR_BPIX_8); rgb = &def_rgb_8; break; } /* add sync polarities */ pcr |= imxfb_mode->pcr & ~(PCR_PCD_MASK | PCR_BPIX_MASK); fbi->pcr = pcr; /* * The LCDC AUS Mode Control Register does not exist on imx1. */ if (!is_imx1_fb(fbi) && imxfb_mode->aus_mode) fbi->lauscr = LAUSCR_AUS_MODE; if (imxfb_mode->pcr & PCR_TFT) fbi->panel_type = PANEL_TYPE_TFT; else if (imxfb_mode->pcr & PCR_COLOR) fbi->panel_type = PANEL_TYPE_CSTN; else fbi->panel_type = PANEL_TYPE_MONOCHROME; /* * Copy the RGB parameters for this display * from the machine specific parameters. */ var->red = rgb->red; var->green = rgb->green; var->blue = rgb->blue; var->transp = rgb->transp; pr_debug("RGBT length = %d:%d:%d:%d\n", var->red.length, var->green.length, var->blue.length, var->transp.length); pr_debug("RGBT offset = %d:%d:%d:%d\n", var->red.offset, var->green.offset, var->blue.offset, var->transp.offset); return 0;} /* * imxfb_set_par(): * Set the user defined part of the display for the specified console */static int imxfb_set_par(struct fb_info *info){ struct imxfb_info *fbi = info->par; struct fb_var_screeninfo *var = &info->var; if (var->bits_per_pixel == 16 || var->bits_per_pixel == 32) info->fix.visual = FB_VISUAL_TRUECOLOR; else if (!fbi->cmap_static) info->fix.visual = FB_VISUAL_PSEUDOCOLOR; else { /* * Some people have weird ideas about wanting static * pseudocolor maps. I suspect their user space * applications are broken. */ info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR; }Lines 1–500 of 1106. Load more
// SPDX-License-Identifier: GPL-2.0-only /* * Freescale i.MX Frame Buffer device driver * * Copyright (C) 2004 Sascha Hauer, Pengutronix * Based on acornfb.c Copyright (C) Russell King. * * Please direct your questions and comments on this driver to the following * email address: * * linux-arm-kernel@lists.arm.linux.org.uk */ #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/string.h> #include <linux/interrupt.h> #include <linux/slab.h> #include <linux/mm.h> #include <linux/fb.h> #include <linux/delay.h> #include <linux/init.h> #include <linux/ioport.h> #include <linux/cpufreq.h> #include <linux/clk.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> #include <linux/io.h> #include <linux/lcd.h> #include <linux/math64.h> #include <linux/of.h> #include <linux/bitfield.h> #include <linux/regulator/consumer.h> #include <video/of_display_timing.h> #include <video/of_videomode.h> #include <video/videomode.h> struct imx_fb_videomode { struct fb_videomode mode; u32 pcr; bool aus_mode; unsigned char bpp; }; /* * Complain if VAR is out of range. */ #define DEBUG_VAR 1 #define DRIVER_NAME "imx-fb" #define LCDC_SSA 0x00 #define LCDC_SIZE 0x04 #define SIZE_XMAX_MASK GENMASK(25, 20) #define YMAX_MASK_IMX1 GENMASK(8, 0) #define YMAX_MASK_IMX21 GENMASK(9, 0) #define LCDC_VPW 0x08 #define VPW_VPW_MASK GENMASK(9, 0) #define LCDC_CPOS 0x0C #define CPOS_CC1 BIT(31) #define CPOS_CC0 BIT(30) #define CPOS_OP BIT(28) #define CPOS_CXP_MASK GENMASK(25, 16) #define LCDC_LCWHB 0x10 #define LCWHB_BK_EN BIT(31) #define LCWHB_CW_MASK GENMASK(28, 24) #define LCWHB_CH_MASK GENMASK(20, 16) #define LCWHB_BD_MASK GENMASK(7, 0) #define LCDC_LCHCC 0x14 #define LCDC_PCR 0x18 #define PCR_TFT BIT(31) #define PCR_COLOR BIT(30) #define PCR_BPIX_MASK GENMASK(27, 25) #define PCR_BPIX_8 3 #define PCR_BPIX_12 4 #define PCR_BPIX_16 5 #define PCR_BPIX_18 6 #define PCR_PCD_MASK GENMASK(5, 0) #define LCDC_HCR 0x1C #define HCR_H_WIDTH_MASK GENMASK(31, 26) #define HCR_H_WAIT_1_MASK GENMASK(15, 8) #define HCR_H_WAIT_2_MASK GENMASK(7, 0) #define LCDC_VCR 0x20 #define VCR_V_WIDTH_MASK GENMASK(31, 26) #define VCR_V_WAIT_1_MASK GENMASK(15, 8) #define VCR_V_WAIT_2_MASK GENMASK(7, 0) #define LCDC_POS 0x24 #define POS_POS_MASK GENMASK(4, 0) #define LCDC_LSCR1 0x28 /* bit fields in imxfb.h */ #define LCDC_PWMR 0x2C /* bit fields in imxfb.h */ #define LCDC_DMACR 0x30 /* bit fields in imxfb.h */ #define LCDC_RMCR 0x34 #define RMCR_LCDC_EN_MX1 BIT(1) #define RMCR_SELF_REF BIT(0) #define LCDC_LCDICR 0x38 #define LCDICR_INT_SYN BIT(2) #define LCDICR_INT_CON BIT(0) #define LCDC_LCDISR 0x40 #define LCDISR_UDR_ERR BIT(3) #define LCDISR_ERR_RES BIT(2) #define LCDISR_EOF BIT(1) #define LCDISR_BOF BIT(0) #define IMXFB_LSCR1_DEFAULT 0x00120300 #define LCDC_LAUSCR 0x80 #define LAUSCR_AUS_MODE BIT(31) /* Used fb-mode. Can be set on kernel command line, therefore file-static. */ static const char *fb_mode; /* * These are the bitfields for each * display depth that we support. */ struct imxfb_rgb { struct fb_bitfield red; struct fb_bitfield green; struct fb_bitfield blue; struct fb_bitfield transp; }; enum imxfb_type { IMX1_FB, IMX21_FB, }; enum imxfb_panel_type { PANEL_TYPE_MONOCHROME, PANEL_TYPE_CSTN, PANEL_TYPE_TFT, }; struct imxfb_info { struct platform_device *pdev; void __iomem *regs; struct clk *clk_ipg; struct clk *clk_ahb; struct clk *clk_per; enum imxfb_type devtype; enum imxfb_panel_type panel_type; bool enabled; /* * These are the addresses we mapped * the framebuffer memory region to. */ dma_addr_t map_dma; u_int map_size; u_int palette_size; dma_addr_t dbar1; dma_addr_t dbar2; u_int pcr; u_int lauscr; u_int pwmr; u_int lscr1; u_int dmacr; bool cmap_inverse; bool cmap_static; struct imx_fb_videomode *mode; int num_modes; struct regulator *lcd_pwr; int lcd_pwr_enabled; }; static const struct platform_device_id imxfb_devtype[] = { { .name = "imx1-fb", .driver_data = IMX1_FB, }, { .name = "imx21-fb", .driver_data = IMX21_FB, }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, imxfb_devtype); static const struct of_device_id imxfb_of_dev_id[] = { { .compatible = "fsl,imx1-fb", .data = &imxfb_devtype[IMX1_FB], }, { .compatible = "fsl,imx21-fb", .data = &imxfb_devtype[IMX21_FB], }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, imxfb_of_dev_id); static inline int is_imx1_fb(struct imxfb_info *fbi) { return fbi->devtype == IMX1_FB; } #define IMX_NAME "IMX" /* * Minimum X and Y resolutions */ #define MIN_XRES 64 #define MIN_YRES 64 /* Actually this really is 18bit support, the lowest 2 bits of each colour * are unused in hardware. We claim to have 24bit support to make software * like X work, which does not support 18bit. */ static struct imxfb_rgb def_rgb_18 = { .red = {.offset = 16, .length = 8,}, .green = {.offset = 8, .length = 8,}, .blue = {.offset = 0, .length = 8,}, .transp = {.offset = 0, .length = 0,}, }; static struct imxfb_rgb def_rgb_16_tft = { .red = {.offset = 11, .length = 5,}, .green = {.offset = 5, .length = 6,}, .blue = {.offset = 0, .length = 5,}, .transp = {.offset = 0, .length = 0,}, }; static struct imxfb_rgb def_rgb_16_stn = { .red = {.offset = 8, .length = 4,}, .green = {.offset = 4, .length = 4,}, .blue = {.offset = 0, .length = 4,}, .transp = {.offset = 0, .length = 0,}, }; static struct imxfb_rgb def_rgb_8 = { .red = {.offset = 0, .length = 8,}, .green = {.offset = 0, .length = 8,}, .blue = {.offset = 0, .length = 8,}, .transp = {.offset = 0, .length = 0,}, }; static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *info); static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf) { chan &= 0xffff; chan >>= 16 - bf->length; return chan << bf->offset; } static int imxfb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue, u_int trans, struct fb_info *info) { struct imxfb_info *fbi = info->par; u_int val, ret = 1; #define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16) if (regno < fbi->palette_size) { val = (CNVT_TOHW(red, 4) << 8) | (CNVT_TOHW(green, 4) << 4) | CNVT_TOHW(blue, 4); writel(val, fbi->regs + 0x800 + (regno << 2)); ret = 0; } return ret; } static int imxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int trans, struct fb_info *info) { struct imxfb_info *fbi = info->par; unsigned int val; int ret = 1; /* * If inverse mode was selected, invert all the colours * rather than the register number. The register number * is what you poke into the framebuffer to produce the * colour you requested. */ if (fbi->cmap_inverse) { red = 0xffff - red; green = 0xffff - green; blue = 0xffff - blue; } /* * If greyscale is true, then we convert the RGB value * to greyscale no mater what visual we are using. */ if (info->var.grayscale) red = green = blue = (19595 * red + 38470 * green + 7471 * blue) >> 16; switch (info->fix.visual) { case FB_VISUAL_TRUECOLOR: /* * 12 or 16-bit True Colour. We encode the RGB value * according to the RGB bitfield information. */ if (regno < 16) { u32 *pal = info->pseudo_palette; val = chan_to_field(red, &info->var.red); val |= chan_to_field(green, &info->var.green); val |= chan_to_field(blue, &info->var.blue); pal[regno] = val; ret = 0; } break; case FB_VISUAL_STATIC_PSEUDOCOLOR: case FB_VISUAL_PSEUDOCOLOR: ret = imxfb_setpalettereg(regno, red, green, blue, trans, info); break; } return ret; } static const struct imx_fb_videomode *imxfb_find_mode(struct imxfb_info *fbi) { struct imx_fb_videomode *m; int i; if (!fb_mode) return &fbi->mode[0]; for (i = 0, m = &fbi->mode[0]; i < fbi->num_modes; i++, m++) { if (!strcmp(m->mode.name, fb_mode)) return m; } return NULL; } /* * imxfb_check_var(): * Round up in the following order: bits_per_pixel, xres, * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale, * bitfields, horizontal timing, vertical timing. */ static int imxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct imxfb_info *fbi = info->par; struct imxfb_rgb *rgb; const struct imx_fb_videomode *imxfb_mode; unsigned long lcd_clk; unsigned long long tmp; u32 pcr = 0; if (var->xres < MIN_XRES) var->xres = MIN_XRES; if (var->yres < MIN_YRES) var->yres = MIN_YRES; imxfb_mode = imxfb_find_mode(fbi); if (!imxfb_mode) return -EINVAL; var->xres = imxfb_mode->mode.xres; var->yres = imxfb_mode->mode.yres; var->bits_per_pixel = imxfb_mode->bpp; var->pixclock = imxfb_mode->mode.pixclock; var->hsync_len = imxfb_mode->mode.hsync_len; var->left_margin = imxfb_mode->mode.left_margin; var->right_margin = imxfb_mode->mode.right_margin; var->vsync_len = imxfb_mode->mode.vsync_len; var->upper_margin = imxfb_mode->mode.upper_margin; var->lower_margin = imxfb_mode->mode.lower_margin; var->sync = imxfb_mode->mode.sync; var->xres_virtual = max(var->xres_virtual, var->xres); var->yres_virtual = max(var->yres_virtual, var->yres); pr_debug("var->bits_per_pixel=%d\n", var->bits_per_pixel); lcd_clk = clk_get_rate(fbi->clk_per); tmp = var->pixclock * (unsigned long long)lcd_clk; do_div(tmp, 1000000); if (do_div(tmp, 1000000) > 500000) tmp++; pcr = (unsigned int)tmp; if (--pcr > PCR_PCD_MASK) { pcr = PCR_PCD_MASK; dev_warn(&fbi->pdev->dev, "Must limit pixel clock to %luHz\n", lcd_clk / pcr); } switch (var->bits_per_pixel) { case 32: pcr |= FIELD_PREP(PCR_BPIX_MASK, PCR_BPIX_18); rgb = &def_rgb_18; break; case 16: default: if (is_imx1_fb(fbi)) pcr |= FIELD_PREP(PCR_BPIX_MASK, PCR_BPIX_12); else pcr |= FIELD_PREP(PCR_BPIX_MASK, PCR_BPIX_16); if (imxfb_mode->pcr & PCR_TFT) rgb = &def_rgb_16_tft; else rgb = &def_rgb_16_stn; break; case 8: pcr |= FIELD_PREP(PCR_BPIX_MASK, PCR_BPIX_8); rgb = &def_rgb_8; break; } /* add sync polarities */ pcr |= imxfb_mode->pcr & ~(PCR_PCD_MASK | PCR_BPIX_MASK); fbi->pcr = pcr; /* * The LCDC AUS Mode Control Register does not exist on imx1. */ if (!is_imx1_fb(fbi) && imxfb_mode->aus_mode) fbi->lauscr = LAUSCR_AUS_MODE; if (imxfb_mode->pcr & PCR_TFT) fbi->panel_type = PANEL_TYPE_TFT; else if (imxfb_mode->pcr & PCR_COLOR) fbi->panel_type = PANEL_TYPE_CSTN; else fbi->panel_type = PANEL_TYPE_MONOCHROME; /* * Copy the RGB parameters for this display * from the machine specific parameters. */ var->red = rgb->red; var->green = rgb->green; var->blue = rgb->blue; var->transp = rgb->transp; pr_debug("RGBT length = %d:%d:%d:%d\n", var->red.length, var->green.length, var->blue.length, var->transp.length); pr_debug("RGBT offset = %d:%d:%d:%d\n", var->red.offset, var->green.offset, var->blue.offset, var->transp.offset); return 0; } /* * imxfb_set_par(): * Set the user defined part of the display for the specified console */ static int imxfb_set_par(struct fb_info *info) { struct imxfb_info *fbi = info->par; struct fb_var_screeninfo *var = &info->var; if (var->bits_per_pixel == 16 || var->bits_per_pixel == 32) info->fix.visual = FB_VISUAL_TRUECOLOR; else if (!fbi->cmap_static) info->fix.visual = FB_VISUAL_PSEUDOCOLOR; else { /* * Some people have weird ideas about wanting static * pseudocolor maps. I suspect their user space * applications are broken. */ info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR; }