summaryrefslogtreecommitdiff
path: root/drivers/video/fbdev/imxfb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/fbdev/imxfb.c')
-rw-r--r--drivers/video/fbdev/imxfb.c179
1 files changed, 102 insertions, 77 deletions
diff --git a/drivers/video/fbdev/imxfb.c b/drivers/video/fbdev/imxfb.c
index 84201c9608d3..a4dbc72f93c3 100644
--- a/drivers/video/fbdev/imxfb.c
+++ b/drivers/video/fbdev/imxfb.c
@@ -1,13 +1,10 @@
+// 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.
*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive for
- * more details.
- *
* Please direct your questions and comments on this driver to the following
* email address:
*
@@ -34,6 +31,7 @@
#include <linux/math64.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/bitfield.h>
#include <linux/regulator/consumer.h>
@@ -41,12 +39,6 @@
#include <video/of_videomode.h>
#include <video/videomode.h>
-#define PCR_TFT (1 << 31)
-#define PCR_BPIX_8 (3 << 25)
-#define PCR_BPIX_12 (4 << 25)
-#define PCR_BPIX_16 (5 << 25)
-#define PCR_BPIX_18 (6 << 25)
-
struct imx_fb_videomode {
struct fb_videomode mode;
u32 pcr;
@@ -64,42 +56,50 @@ struct imx_fb_videomode {
#define LCDC_SSA 0x00
#define LCDC_SIZE 0x04
-#define SIZE_XMAX(x) ((((x) >> 4) & 0x3f) << 20)
+#define SIZE_XMAX_MASK GENMASK(25, 20)
-#define YMAX_MASK_IMX1 0x1ff
-#define YMAX_MASK_IMX21 0x3ff
+#define YMAX_MASK_IMX1 GENMASK(8, 0)
+#define YMAX_MASK_IMX21 GENMASK(9, 0)
#define LCDC_VPW 0x08
-#define VPW_VPW(x) ((x) & 0x3ff)
+#define VPW_VPW_MASK GENMASK(9, 0)
#define LCDC_CPOS 0x0C
-#define CPOS_CC1 (1<<31)
-#define CPOS_CC0 (1<<30)
-#define CPOS_OP (1<<28)
-#define CPOS_CXP(x) (((x) & 3ff) << 16)
+#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 (1<<31)
-#define LCWHB_CW(w) (((w) & 0x1f) << 24)
-#define LCWHB_CH(h) (((h) & 0x1f) << 16)
-#define LCWHB_BD(x) ((x) & 0xff)
+#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(x) (((x) & 0x3f) << 26)
-#define HCR_H_WAIT_1(x) (((x) & 0xff) << 8)
-#define HCR_H_WAIT_2(x) ((x) & 0xff)
+#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(x) (((x) & 0x3f) << 26)
-#define VCR_V_WAIT_1(x) (((x) & 0xff) << 8)
-#define VCR_V_WAIT_2(x) ((x) & 0xff)
+#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(x) ((x) & 1f)
+#define POS_POS_MASK GENMASK(4, 0)
#define LCDC_LSCR1 0x28
/* bit fields in imxfb.h */
@@ -112,24 +112,24 @@ struct imx_fb_videomode {
#define LCDC_RMCR 0x34
-#define RMCR_LCDC_EN_MX1 (1<<1)
+#define RMCR_LCDC_EN_MX1 BIT(1)
-#define RMCR_SELF_REF (1<<0)
+#define RMCR_SELF_REF BIT(0)
#define LCDC_LCDICR 0x38
-#define LCDICR_INT_SYN (1<<2)
-#define LCDICR_INT_CON (1)
+#define LCDICR_INT_SYN BIT(2)
+#define LCDICR_INT_CON BIT(0)
#define LCDC_LCDISR 0x40
-#define LCDISR_UDR_ERR (1<<3)
-#define LCDISR_ERR_RES (1<<2)
-#define LCDISR_EOF (1<<1)
-#define LCDISR_BOF (1<<0)
+#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 (1<<31)
+#define LAUSCR_AUS_MODE BIT(31)
/* Used fb-mode. Can be set on kernel command line, therefore file-static. */
static const char *fb_mode;
@@ -150,6 +150,12 @@ enum imxfb_type {
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;
@@ -157,6 +163,7 @@ struct imxfb_info {
struct clk *clk_ahb;
struct clk *clk_per;
enum imxfb_type devtype;
+ enum imxfb_panel_type panel_type;
bool enabled;
/*
@@ -273,10 +280,10 @@ static int imxfb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
struct imxfb_info *fbi = info->par;
u_int val, ret = 1;
-#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
+#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(green, 4) << 4) |
CNVT_TOHW(blue, 4);
writel(val, fbi->regs + 0x800 + (regno << 2));
@@ -405,23 +412,23 @@ static int imxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
pcr = (unsigned int)tmp;
- if (--pcr > 0x3F) {
- pcr = 0x3F;
- printk(KERN_WARNING "Must limit pixel clock to %luHz\n",
- lcd_clk / pcr);
+ 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 |= PCR_BPIX_18;
+ pcr |= FIELD_PREP(PCR_BPIX_MASK, PCR_BPIX_18);
rgb = &def_rgb_18;
break;
case 16:
default:
if (is_imx1_fb(fbi))
- pcr |= PCR_BPIX_12;
+ pcr |= FIELD_PREP(PCR_BPIX_MASK, PCR_BPIX_12);
else
- pcr |= PCR_BPIX_16;
+ pcr |= FIELD_PREP(PCR_BPIX_MASK, PCR_BPIX_16);
if (imxfb_mode->pcr & PCR_TFT)
rgb = &def_rgb_16_tft;
@@ -429,13 +436,13 @@ static int imxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
rgb = &def_rgb_16_stn;
break;
case 8:
- pcr |= PCR_BPIX_8;
+ pcr |= FIELD_PREP(PCR_BPIX_MASK, PCR_BPIX_8);
rgb = &def_rgb_8;
break;
}
/* add sync polarities */
- pcr |= imxfb_mode->pcr & ~(0x3f | (7 << 25));
+ pcr |= imxfb_mode->pcr & ~(PCR_PCD_MASK | PCR_BPIX_MASK);
fbi->pcr = pcr;
/*
@@ -444,6 +451,13 @@ static int imxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
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.
@@ -506,7 +520,7 @@ static int imxfb_enable_controller(struct imxfb_info *fbi)
writel(fbi->map_dma, fbi->regs + LCDC_SSA);
/* panning offset 0 (0 pixel offset) */
- writel(0x00000000, fbi->regs + LCDC_POS);
+ writel(FIELD_PREP(POS_POS_MASK, 0), fbi->regs + LCDC_POS);
/* disable hardware cursor */
writel(readl(fbi->regs + LCDC_CPOS) & ~(CPOS_CC0 | CPOS_CC1),
@@ -562,7 +576,7 @@ static int imxfb_blank(int blank, struct fb_info *info)
{
struct imxfb_info *fbi = info->par;
- pr_debug("imxfb_blank: blank=%d\n", blank);
+ pr_debug("%s: blank=%d\n", __func__, blank);
switch (blank) {
case FB_BLANK_POWERDOWN:
@@ -596,6 +610,7 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf
{
struct imxfb_info *fbi = info->par;
u32 ymax_mask = is_imx1_fb(fbi) ? YMAX_MASK_IMX1 : YMAX_MASK_IMX21;
+ u8 left_margin_low;
pr_debug("var: xres=%d hslen=%d lm=%d rm=%d\n",
var->xres, var->hsync_len,
@@ -604,49 +619,59 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf
var->yres, var->vsync_len,
var->upper_margin, var->lower_margin);
+ if (fbi->panel_type == PANEL_TYPE_TFT)
+ left_margin_low = 3;
+ else if (fbi->panel_type == PANEL_TYPE_CSTN)
+ left_margin_low = 2;
+ else
+ left_margin_low = 0;
+
#if DEBUG_VAR
if (var->xres < 16 || var->xres > 1024)
- printk(KERN_ERR "%s: invalid xres %d\n",
+ dev_err(&fbi->pdev->dev, "%s: invalid xres %d\n",
info->fix.id, var->xres);
if (var->hsync_len < 1 || var->hsync_len > 64)
- printk(KERN_ERR "%s: invalid hsync_len %d\n",
+ dev_err(&fbi->pdev->dev, "%s: invalid hsync_len %d\n",
info->fix.id, var->hsync_len);
- if (var->left_margin < 3 || var->left_margin > 255)
- printk(KERN_ERR "%s: invalid left_margin %d\n",
+ if (var->left_margin < left_margin_low || var->left_margin > 255)
+ dev_err(&fbi->pdev->dev, "%s: invalid left_margin %d\n",
info->fix.id, var->left_margin);
if (var->right_margin < 1 || var->right_margin > 255)
- printk(KERN_ERR "%s: invalid right_margin %d\n",
+ dev_err(&fbi->pdev->dev, "%s: invalid right_margin %d\n",
info->fix.id, var->right_margin);
if (var->yres < 1 || var->yres > ymax_mask)
- printk(KERN_ERR "%s: invalid yres %d\n",
+ dev_err(&fbi->pdev->dev, "%s: invalid yres %d\n",
info->fix.id, var->yres);
if (var->vsync_len > 100)
- printk(KERN_ERR "%s: invalid vsync_len %d\n",
+ dev_err(&fbi->pdev->dev, "%s: invalid vsync_len %d\n",
info->fix.id, var->vsync_len);
if (var->upper_margin > 63)
- printk(KERN_ERR "%s: invalid upper_margin %d\n",
+ dev_err(&fbi->pdev->dev, "%s: invalid upper_margin %d\n",
info->fix.id, var->upper_margin);
if (var->lower_margin > 255)
- printk(KERN_ERR "%s: invalid lower_margin %d\n",
+ dev_err(&fbi->pdev->dev, "%s: invalid lower_margin %d\n",
info->fix.id, var->lower_margin);
#endif
/* physical screen start address */
- writel(VPW_VPW(var->xres * var->bits_per_pixel / 8 / 4),
- fbi->regs + LCDC_VPW);
+ writel(FIELD_PREP(VPW_VPW_MASK,
+ var->xres * var->bits_per_pixel / 8 / 4),
+ fbi->regs + LCDC_VPW);
- writel(HCR_H_WIDTH(var->hsync_len - 1) |
- HCR_H_WAIT_1(var->right_margin - 1) |
- HCR_H_WAIT_2(var->left_margin - 3),
- fbi->regs + LCDC_HCR);
+ writel(FIELD_PREP(HCR_H_WIDTH_MASK, var->hsync_len - 1) |
+ FIELD_PREP(HCR_H_WAIT_1_MASK, var->right_margin - 1) |
+ FIELD_PREP(HCR_H_WAIT_2_MASK,
+ var->left_margin - left_margin_low),
+ fbi->regs + LCDC_HCR);
- writel(VCR_V_WIDTH(var->vsync_len) |
- VCR_V_WAIT_1(var->lower_margin) |
- VCR_V_WAIT_2(var->upper_margin),
- fbi->regs + LCDC_VCR);
+ writel(FIELD_PREP(VCR_V_WIDTH_MASK, var->vsync_len) |
+ FIELD_PREP(VCR_V_WAIT_1_MASK, var->lower_margin) |
+ FIELD_PREP(VCR_V_WAIT_2_MASK, var->upper_margin),
+ fbi->regs + LCDC_VCR);
- writel(SIZE_XMAX(var->xres) | (var->yres & ymax_mask),
- fbi->regs + LCDC_SIZE);
+ writel(FIELD_PREP(SIZE_XMAX_MASK, var->xres >> 4) |
+ (var->yres & ymax_mask),
+ fbi->regs + LCDC_SIZE);
writel(fbi->pcr, fbi->regs + LCDC_PCR);
if (fbi->pwmr)
@@ -669,8 +694,6 @@ static int imxfb_init_fbinfo(struct platform_device *pdev)
struct imxfb_info *fbi = info->par;
struct device_node *np;
- pr_debug("%s\n",__func__);
-
info->pseudo_palette = devm_kmalloc_array(&pdev->dev, 16,
sizeof(u32), GFP_KERNEL);
if (!info->pseudo_palette)
@@ -678,6 +701,7 @@ static int imxfb_init_fbinfo(struct platform_device *pdev)
memset(fbi, 0, sizeof(struct imxfb_info));
+ fbi->pdev = pdev;
fbi->devtype = pdev->id_entry->driver_data;
strscpy(info->fix.id, IMX_NAME, sizeof(info->fix.id));
@@ -922,8 +946,10 @@ static int imxfb_probe(struct platform_device *pdev)
if (ret)
goto failed_init;
- /* Calculate maximum bytes used per pixel. In most cases this should
- * be the same as m->bpp/8 */
+ /*
+ * Calculate maximum bytes used per pixel. In most cases this should
+ * be the same as m->bpp/8
+ */
m = &fbi->mode[0];
bytes_per_pixel = (m->bpp + 7) / 8;
for (i = 0; i < fbi->num_modes; i++, m++)
@@ -1021,7 +1047,6 @@ static int imxfb_probe(struct platform_device *pdev)
lcd->props.max_contrast = 0xff;
imxfb_enable_controller(fbi);
- fbi->pdev = pdev;
return 0;