^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * Freescale i.MX Frame Buffer device driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2004 Sascha Hauer, Pengutronix
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Based on acornfb.c Copyright (C) Russell King.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * This file is subject to the terms and conditions of the GNU General Public
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * License. See the file COPYING in the main directory of this archive for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Please direct your questions and comments on this driver to the following
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * email address:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * linux-arm-kernel@lists.arm.linux.org.uk
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/ioport.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/cpufreq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/dma-mapping.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <linux/lcd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <linux/math64.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include <linux/of_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include <linux/regulator/consumer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #include <video/of_display_timing.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #include <video/of_videomode.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #include <video/videomode.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #include <linux/platform_data/video-imxfb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * Complain if VAR is out of range.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define DEBUG_VAR 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #define DRIVER_NAME "imx-fb"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #define LCDC_SSA 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #define LCDC_SIZE 0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #define SIZE_XMAX(x) ((((x) >> 4) & 0x3f) << 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) #define YMAX_MASK_IMX1 0x1ff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #define YMAX_MASK_IMX21 0x3ff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define LCDC_VPW 0x08
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) #define VPW_VPW(x) ((x) & 0x3ff)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) #define LCDC_CPOS 0x0C
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) #define CPOS_CC1 (1<<31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) #define CPOS_CC0 (1<<30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) #define CPOS_OP (1<<28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) #define CPOS_CXP(x) (((x) & 3ff) << 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) #define LCDC_LCWHB 0x10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) #define LCWHB_BK_EN (1<<31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) #define LCWHB_CW(w) (((w) & 0x1f) << 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) #define LCWHB_CH(h) (((h) & 0x1f) << 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) #define LCWHB_BD(x) ((x) & 0xff)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) #define LCDC_LCHCC 0x14
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) #define LCDC_PCR 0x18
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) #define LCDC_HCR 0x1C
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) #define HCR_H_WIDTH(x) (((x) & 0x3f) << 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) #define HCR_H_WAIT_1(x) (((x) & 0xff) << 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) #define HCR_H_WAIT_2(x) ((x) & 0xff)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) #define LCDC_VCR 0x20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) #define VCR_V_WIDTH(x) (((x) & 0x3f) << 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) #define VCR_V_WAIT_1(x) (((x) & 0xff) << 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) #define VCR_V_WAIT_2(x) ((x) & 0xff)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) #define LCDC_POS 0x24
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) #define POS_POS(x) ((x) & 1f)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) #define LCDC_LSCR1 0x28
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) /* bit fields in imxfb.h */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) #define LCDC_PWMR 0x2C
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) /* bit fields in imxfb.h */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) #define LCDC_DMACR 0x30
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) /* bit fields in imxfb.h */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) #define LCDC_RMCR 0x34
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) #define RMCR_LCDC_EN_MX1 (1<<1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) #define RMCR_SELF_REF (1<<0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) #define LCDC_LCDICR 0x38
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) #define LCDICR_INT_SYN (1<<2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) #define LCDICR_INT_CON (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) #define LCDC_LCDISR 0x40
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) #define LCDISR_UDR_ERR (1<<3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) #define LCDISR_ERR_RES (1<<2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) #define LCDISR_EOF (1<<1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) #define LCDISR_BOF (1<<0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) #define IMXFB_LSCR1_DEFAULT 0x00120300
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) #define LCDC_LAUSCR 0x80
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) #define LAUSCR_AUS_MODE (1<<31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) /* Used fb-mode. Can be set on kernel command line, therefore file-static. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) static const char *fb_mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) * These are the bitfields for each
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) * display depth that we support.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) struct imxfb_rgb {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) struct fb_bitfield red;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) struct fb_bitfield green;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) struct fb_bitfield blue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) struct fb_bitfield transp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) enum imxfb_type {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) IMX1_FB,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) IMX21_FB,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) struct imxfb_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) struct platform_device *pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) void __iomem *regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) struct clk *clk_ipg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) struct clk *clk_ahb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) struct clk *clk_per;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) enum imxfb_type devtype;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) bool enabled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) * These are the addresses we mapped
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) * the framebuffer memory region to.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) dma_addr_t map_dma;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) u_int map_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) u_int palette_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) dma_addr_t dbar1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) dma_addr_t dbar2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) u_int pcr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) u_int lauscr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) u_int pwmr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) u_int lscr1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) u_int dmacr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) bool cmap_inverse;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) bool cmap_static;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) struct imx_fb_videomode *mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) int num_modes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) struct regulator *lcd_pwr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) int lcd_pwr_enabled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) static const struct platform_device_id imxfb_devtype[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) .name = "imx1-fb",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) .driver_data = IMX1_FB,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) .name = "imx21-fb",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) .driver_data = IMX21_FB,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) /* sentinel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) MODULE_DEVICE_TABLE(platform, imxfb_devtype);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) static const struct of_device_id imxfb_of_dev_id[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) .compatible = "fsl,imx1-fb",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) .data = &imxfb_devtype[IMX1_FB],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) .compatible = "fsl,imx21-fb",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) .data = &imxfb_devtype[IMX21_FB],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) /* sentinel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) MODULE_DEVICE_TABLE(of, imxfb_of_dev_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) static inline int is_imx1_fb(struct imxfb_info *fbi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) return fbi->devtype == IMX1_FB;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) #define IMX_NAME "IMX"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) * Minimum X and Y resolutions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) #define MIN_XRES 64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) #define MIN_YRES 64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) /* Actually this really is 18bit support, the lowest 2 bits of each colour
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) * are unused in hardware. We claim to have 24bit support to make software
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) * like X work, which does not support 18bit.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) static struct imxfb_rgb def_rgb_18 = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) .red = {.offset = 16, .length = 8,},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) .green = {.offset = 8, .length = 8,},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) .blue = {.offset = 0, .length = 8,},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) .transp = {.offset = 0, .length = 0,},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) static struct imxfb_rgb def_rgb_16_tft = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) .red = {.offset = 11, .length = 5,},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) .green = {.offset = 5, .length = 6,},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) .blue = {.offset = 0, .length = 5,},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) .transp = {.offset = 0, .length = 0,},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) static struct imxfb_rgb def_rgb_16_stn = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) .red = {.offset = 8, .length = 4,},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) .green = {.offset = 4, .length = 4,},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) .blue = {.offset = 0, .length = 4,},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) .transp = {.offset = 0, .length = 0,},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) static struct imxfb_rgb def_rgb_8 = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) .red = {.offset = 0, .length = 8,},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) .green = {.offset = 0, .length = 8,},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) .blue = {.offset = 0, .length = 8,},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) .transp = {.offset = 0, .length = 0,},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) static int imxfb_activate_var(struct fb_var_screeninfo *var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) struct fb_info *info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) chan &= 0xffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) chan >>= 16 - bf->length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) return chan << bf->offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) static int imxfb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) u_int trans, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) struct imxfb_info *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) u_int val, ret = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) #define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) if (regno < fbi->palette_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) val = (CNVT_TOHW(red, 4) << 8) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) (CNVT_TOHW(green,4) << 4) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) CNVT_TOHW(blue, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) writel(val, fbi->regs + 0x800 + (regno << 2));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) static int imxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) u_int trans, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) struct imxfb_info *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) unsigned int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) int ret = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) * If inverse mode was selected, invert all the colours
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) * rather than the register number. The register number
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) * is what you poke into the framebuffer to produce the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) * colour you requested.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) if (fbi->cmap_inverse) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) red = 0xffff - red;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) green = 0xffff - green;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) blue = 0xffff - blue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) * If greyscale is true, then we convert the RGB value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) * to greyscale no mater what visual we are using.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) if (info->var.grayscale)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) red = green = blue = (19595 * red + 38470 * green +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 7471 * blue) >> 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) switch (info->fix.visual) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) case FB_VISUAL_TRUECOLOR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) * 12 or 16-bit True Colour. We encode the RGB value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) * according to the RGB bitfield information.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) if (regno < 16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) u32 *pal = info->pseudo_palette;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) val = chan_to_field(red, &info->var.red);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) val |= chan_to_field(green, &info->var.green);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) val |= chan_to_field(blue, &info->var.blue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) pal[regno] = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) case FB_VISUAL_STATIC_PSEUDOCOLOR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) case FB_VISUAL_PSEUDOCOLOR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) ret = imxfb_setpalettereg(regno, red, green, blue, trans, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) static const struct imx_fb_videomode *imxfb_find_mode(struct imxfb_info *fbi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) struct imx_fb_videomode *m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) if (!fb_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) return &fbi->mode[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) for (i = 0, m = &fbi->mode[0]; i < fbi->num_modes; i++, m++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) if (!strcmp(m->mode.name, fb_mode))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) return m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) * imxfb_check_var():
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) * Round up in the following order: bits_per_pixel, xres,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) * bitfields, horizontal timing, vertical timing.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) static int imxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) struct imxfb_info *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) struct imxfb_rgb *rgb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) const struct imx_fb_videomode *imxfb_mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) unsigned long lcd_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) unsigned long long tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) u32 pcr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) if (var->xres < MIN_XRES)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) var->xres = MIN_XRES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) if (var->yres < MIN_YRES)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) var->yres = MIN_YRES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) imxfb_mode = imxfb_find_mode(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) if (!imxfb_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) var->xres = imxfb_mode->mode.xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) var->yres = imxfb_mode->mode.yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) var->bits_per_pixel = imxfb_mode->bpp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) var->pixclock = imxfb_mode->mode.pixclock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) var->hsync_len = imxfb_mode->mode.hsync_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) var->left_margin = imxfb_mode->mode.left_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) var->right_margin = imxfb_mode->mode.right_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) var->vsync_len = imxfb_mode->mode.vsync_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) var->upper_margin = imxfb_mode->mode.upper_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) var->lower_margin = imxfb_mode->mode.lower_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) var->sync = imxfb_mode->mode.sync;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) var->xres_virtual = max(var->xres_virtual, var->xres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) var->yres_virtual = max(var->yres_virtual, var->yres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) pr_debug("var->bits_per_pixel=%d\n", var->bits_per_pixel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) lcd_clk = clk_get_rate(fbi->clk_per);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) tmp = var->pixclock * (unsigned long long)lcd_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) do_div(tmp, 1000000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) if (do_div(tmp, 1000000) > 500000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) tmp++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) pcr = (unsigned int)tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) if (--pcr > 0x3F) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) pcr = 0x3F;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) printk(KERN_WARNING "Must limit pixel clock to %luHz\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) lcd_clk / pcr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) switch (var->bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) pcr |= PCR_BPIX_18;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) rgb = &def_rgb_18;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) if (is_imx1_fb(fbi))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) pcr |= PCR_BPIX_12;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) pcr |= PCR_BPIX_16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) if (imxfb_mode->pcr & PCR_TFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) rgb = &def_rgb_16_tft;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) rgb = &def_rgb_16_stn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) pcr |= PCR_BPIX_8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) rgb = &def_rgb_8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) /* add sync polarities */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) pcr |= imxfb_mode->pcr & ~(0x3f | (7 << 25));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) fbi->pcr = pcr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) * The LCDC AUS Mode Control Register does not exist on imx1.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) if (!is_imx1_fb(fbi) && imxfb_mode->aus_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) fbi->lauscr = LAUSCR_AUS_MODE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) * Copy the RGB parameters for this display
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) * from the machine specific parameters.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) var->red = rgb->red;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) var->green = rgb->green;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) var->blue = rgb->blue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) var->transp = rgb->transp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) pr_debug("RGBT length = %d:%d:%d:%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) var->red.length, var->green.length, var->blue.length,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) var->transp.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) pr_debug("RGBT offset = %d:%d:%d:%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) var->red.offset, var->green.offset, var->blue.offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) var->transp.offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) * imxfb_set_par():
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) * Set the user defined part of the display for the specified console
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) static int imxfb_set_par(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) struct imxfb_info *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) struct fb_var_screeninfo *var = &info->var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) if (var->bits_per_pixel == 16 || var->bits_per_pixel == 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) info->fix.visual = FB_VISUAL_TRUECOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) else if (!fbi->cmap_static)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) * Some people have weird ideas about wanting static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) * pseudocolor maps. I suspect their user space
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) * applications are broken.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) info->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) fbi->palette_size = var->bits_per_pixel == 8 ? 256 : 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) imxfb_activate_var(var, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) static int imxfb_enable_controller(struct imxfb_info *fbi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) if (fbi->enabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) pr_debug("Enabling LCD controller\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) writel(fbi->map_dma, fbi->regs + LCDC_SSA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) /* panning offset 0 (0 pixel offset) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) writel(0x00000000, fbi->regs + LCDC_POS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) /* disable hardware cursor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) writel(readl(fbi->regs + LCDC_CPOS) & ~(CPOS_CC0 | CPOS_CC1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) fbi->regs + LCDC_CPOS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) * RMCR_LCDC_EN_MX1 is present on i.MX1 only, but doesn't hurt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) * on other SoCs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) writel(RMCR_LCDC_EN_MX1, fbi->regs + LCDC_RMCR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) ret = clk_prepare_enable(fbi->clk_ipg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) goto err_enable_ipg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) ret = clk_prepare_enable(fbi->clk_ahb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) goto err_enable_ahb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) ret = clk_prepare_enable(fbi->clk_per);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) goto err_enable_per;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) fbi->enabled = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) err_enable_per:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) clk_disable_unprepare(fbi->clk_ahb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) err_enable_ahb:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) clk_disable_unprepare(fbi->clk_ipg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) err_enable_ipg:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) writel(0, fbi->regs + LCDC_RMCR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) static void imxfb_disable_controller(struct imxfb_info *fbi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) if (!fbi->enabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) pr_debug("Disabling LCD controller\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) clk_disable_unprepare(fbi->clk_per);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) clk_disable_unprepare(fbi->clk_ahb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) clk_disable_unprepare(fbi->clk_ipg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) fbi->enabled = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) writel(0, fbi->regs + LCDC_RMCR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) static int imxfb_blank(int blank, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) struct imxfb_info *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) pr_debug("imxfb_blank: blank=%d\n", blank);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) switch (blank) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) case FB_BLANK_POWERDOWN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) case FB_BLANK_VSYNC_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) case FB_BLANK_HSYNC_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) case FB_BLANK_NORMAL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) imxfb_disable_controller(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) case FB_BLANK_UNBLANK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) return imxfb_enable_controller(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) static const struct fb_ops imxfb_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) .fb_check_var = imxfb_check_var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) .fb_set_par = imxfb_set_par,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) .fb_setcolreg = imxfb_setcolreg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) .fb_fillrect = cfb_fillrect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) .fb_copyarea = cfb_copyarea,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) .fb_imageblit = cfb_imageblit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) .fb_blank = imxfb_blank,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) * imxfb_activate_var():
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) * Configures LCD Controller based on entries in var parameter. Settings are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) * only written to the controller if changes were made.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) struct imxfb_info *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) u32 ymax_mask = is_imx1_fb(fbi) ? YMAX_MASK_IMX1 : YMAX_MASK_IMX21;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) pr_debug("var: xres=%d hslen=%d lm=%d rm=%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) var->xres, var->hsync_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) var->left_margin, var->right_margin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) pr_debug("var: yres=%d vslen=%d um=%d bm=%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) var->yres, var->vsync_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) var->upper_margin, var->lower_margin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) #if DEBUG_VAR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) if (var->xres < 16 || var->xres > 1024)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) printk(KERN_ERR "%s: invalid xres %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) info->fix.id, var->xres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) if (var->hsync_len < 1 || var->hsync_len > 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) printk(KERN_ERR "%s: invalid hsync_len %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) info->fix.id, var->hsync_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) if (var->left_margin > 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) printk(KERN_ERR "%s: invalid left_margin %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) info->fix.id, var->left_margin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) if (var->right_margin > 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) printk(KERN_ERR "%s: invalid right_margin %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) info->fix.id, var->right_margin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) if (var->yres < 1 || var->yres > ymax_mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) printk(KERN_ERR "%s: invalid yres %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) info->fix.id, var->yres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) if (var->vsync_len > 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) printk(KERN_ERR "%s: invalid vsync_len %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) info->fix.id, var->vsync_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) if (var->upper_margin > 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) printk(KERN_ERR "%s: invalid upper_margin %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) info->fix.id, var->upper_margin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) if (var->lower_margin > 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) printk(KERN_ERR "%s: invalid lower_margin %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) info->fix.id, var->lower_margin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) /* physical screen start address */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) writel(VPW_VPW(var->xres * var->bits_per_pixel / 8 / 4),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) fbi->regs + LCDC_VPW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) writel(HCR_H_WIDTH(var->hsync_len - 1) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) HCR_H_WAIT_1(var->right_margin - 1) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) HCR_H_WAIT_2(var->left_margin - 3),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) fbi->regs + LCDC_HCR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) writel(VCR_V_WIDTH(var->vsync_len) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) VCR_V_WAIT_1(var->lower_margin) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) VCR_V_WAIT_2(var->upper_margin),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) fbi->regs + LCDC_VCR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) writel(SIZE_XMAX(var->xres) | (var->yres & ymax_mask),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) fbi->regs + LCDC_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) writel(fbi->pcr, fbi->regs + LCDC_PCR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) if (fbi->pwmr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) writel(fbi->pwmr, fbi->regs + LCDC_PWMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) writel(fbi->lscr1, fbi->regs + LCDC_LSCR1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) /* dmacr = 0 is no valid value, as we need DMA control marks. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) if (fbi->dmacr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) writel(fbi->dmacr, fbi->regs + LCDC_DMACR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) if (fbi->lauscr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) writel(fbi->lauscr, fbi->regs + LCDC_LAUSCR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) static int imxfb_init_fbinfo(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) struct imx_fb_platform_data *pdata = dev_get_platdata(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) struct fb_info *info = dev_get_drvdata(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) struct imxfb_info *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) struct device_node *np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) pr_debug("%s\n",__func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) info->pseudo_palette = kmalloc_array(16, sizeof(u32), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) if (!info->pseudo_palette)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) memset(fbi, 0, sizeof(struct imxfb_info));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) fbi->devtype = pdev->id_entry->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) strlcpy(info->fix.id, IMX_NAME, sizeof(info->fix.id));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) info->fix.type = FB_TYPE_PACKED_PIXELS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) info->fix.type_aux = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) info->fix.xpanstep = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) info->fix.ypanstep = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) info->fix.ywrapstep = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) info->fix.accel = FB_ACCEL_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) info->var.nonstd = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) info->var.activate = FB_ACTIVATE_NOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) info->var.height = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) info->var.width = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) info->var.accel_flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) info->var.vmode = FB_VMODE_NONINTERLACED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) info->fbops = &imxfb_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) info->flags = FBINFO_FLAG_DEFAULT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) FBINFO_READS_FAST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) if (pdata) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) fbi->lscr1 = pdata->lscr1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) fbi->dmacr = pdata->dmacr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) fbi->pwmr = pdata->pwmr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) np = pdev->dev.of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) info->var.grayscale = of_property_read_bool(np,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) "cmap-greyscale");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) fbi->cmap_inverse = of_property_read_bool(np, "cmap-inverse");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) fbi->cmap_static = of_property_read_bool(np, "cmap-static");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) fbi->lscr1 = IMXFB_LSCR1_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) of_property_read_u32(np, "fsl,lpccr", &fbi->pwmr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) of_property_read_u32(np, "fsl,lscr1", &fbi->lscr1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) of_property_read_u32(np, "fsl,dmacr", &fbi->dmacr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) static int imxfb_of_read_mode(struct device *dev, struct device_node *np,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) struct imx_fb_videomode *imxfb_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) struct fb_videomode *of_mode = &imxfb_mode->mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) u32 bpp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) u32 pcr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) ret = of_property_read_string(np, "model", &of_mode->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) of_mode->name = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) ret = of_get_fb_videomode(np, of_mode, OF_USE_NATIVE_MODE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) dev_err(dev, "Failed to get videomode from DT\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) ret = of_property_read_u32(np, "bits-per-pixel", &bpp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) ret |= of_property_read_u32(np, "fsl,pcr", &pcr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) dev_err(dev, "Failed to read bpp and pcr from DT\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) if (bpp < 1 || bpp > 255) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) dev_err(dev, "Bits per pixel have to be between 1 and 255\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) imxfb_mode->bpp = bpp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) imxfb_mode->pcr = pcr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) * fsl,aus-mode is optional
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) imxfb_mode->aus_mode = of_property_read_bool(np, "fsl,aus-mode");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) static int imxfb_lcd_check_fb(struct lcd_device *lcddev, struct fb_info *fi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) struct imxfb_info *fbi = dev_get_drvdata(&lcddev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) if (!fi || fi->par == fbi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) static int imxfb_lcd_get_contrast(struct lcd_device *lcddev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) struct imxfb_info *fbi = dev_get_drvdata(&lcddev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) return fbi->pwmr & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) static int imxfb_lcd_set_contrast(struct lcd_device *lcddev, int contrast)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) struct imxfb_info *fbi = dev_get_drvdata(&lcddev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) if (fbi->pwmr && fbi->enabled) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) if (contrast > 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) contrast = 255;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) else if (contrast < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) contrast = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) fbi->pwmr &= ~0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) fbi->pwmr |= contrast;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) writel(fbi->pwmr, fbi->regs + LCDC_PWMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) static int imxfb_lcd_get_power(struct lcd_device *lcddev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) struct imxfb_info *fbi = dev_get_drvdata(&lcddev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) if (!IS_ERR(fbi->lcd_pwr) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) !regulator_is_enabled(fbi->lcd_pwr))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) return FB_BLANK_POWERDOWN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) return FB_BLANK_UNBLANK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) static int imxfb_regulator_set(struct imxfb_info *fbi, int enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) if (enable == fbi->lcd_pwr_enabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) if (enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) ret = regulator_enable(fbi->lcd_pwr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) ret = regulator_disable(fbi->lcd_pwr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) if (ret == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) fbi->lcd_pwr_enabled = enable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) static int imxfb_lcd_set_power(struct lcd_device *lcddev, int power)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) struct imxfb_info *fbi = dev_get_drvdata(&lcddev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) if (!IS_ERR(fbi->lcd_pwr))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) return imxfb_regulator_set(fbi, power == FB_BLANK_UNBLANK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) static struct lcd_ops imxfb_lcd_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) .check_fb = imxfb_lcd_check_fb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) .get_contrast = imxfb_lcd_get_contrast,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) .set_contrast = imxfb_lcd_set_contrast,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) .get_power = imxfb_lcd_get_power,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) .set_power = imxfb_lcd_set_power,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) static int imxfb_setup(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) char *opt, *options = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) if (fb_get_options("imxfb", &options))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) if (!options || !*options)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) while ((opt = strsep(&options, ",")) != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) if (!*opt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) fb_mode = opt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) static int imxfb_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) struct imxfb_info *fbi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) struct lcd_device *lcd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) struct fb_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) struct imx_fb_platform_data *pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) struct imx_fb_videomode *m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) const struct of_device_id *of_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) int ret, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) int bytes_per_pixel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) dev_info(&pdev->dev, "i.MX Framebuffer driver\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) ret = imxfb_setup();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) of_id = of_match_device(imxfb_of_dev_id, &pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) if (of_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) pdev->id_entry = of_id->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) if (!res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) pdata = dev_get_platdata(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) info = framebuffer_alloc(sizeof(struct imxfb_info), &pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) if (!info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) platform_set_drvdata(pdev, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) ret = imxfb_init_fbinfo(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) goto failed_init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) if (pdata) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) if (!fb_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) fb_mode = pdata->mode[0].mode.name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) fbi->mode = pdata->mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) fbi->num_modes = pdata->num_modes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) struct device_node *display_np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) fb_mode = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) display_np = of_parse_phandle(pdev->dev.of_node, "display", 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) if (!display_np) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) dev_err(&pdev->dev, "No display defined in devicetree\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) goto failed_of_parse;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) * imxfb does not support more modes, we choose only the native
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) * mode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) fbi->num_modes = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) fbi->mode = devm_kzalloc(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) sizeof(struct imx_fb_videomode), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) if (!fbi->mode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) goto failed_of_parse;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) ret = imxfb_of_read_mode(&pdev->dev, display_np, fbi->mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) goto failed_of_parse;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) /* Calculate maximum bytes used per pixel. In most cases this should
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) * be the same as m->bpp/8 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) m = &fbi->mode[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) bytes_per_pixel = (m->bpp + 7) / 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) for (i = 0; i < fbi->num_modes; i++, m++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) info->fix.smem_len = max_t(size_t, info->fix.smem_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) m->mode.xres * m->mode.yres * bytes_per_pixel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) res = request_mem_region(res->start, resource_size(res),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) DRIVER_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) if (!res) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) ret = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) goto failed_req;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) fbi->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) if (IS_ERR(fbi->clk_ipg)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) ret = PTR_ERR(fbi->clk_ipg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) goto failed_getclock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) * The LCDC controller does not have an enable bit. The
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) * controller starts directly when the clocks are enabled.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) * If the clocks are enabled when the controller is not yet
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) * programmed with proper register values (enabled at the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) * bootloader, for example) then it just goes into some undefined
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) * state.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) * To avoid this issue, let's enable and disable LCDC IPG clock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) * so that we force some kind of 'reset' to the LCDC block.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) ret = clk_prepare_enable(fbi->clk_ipg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) goto failed_getclock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) clk_disable_unprepare(fbi->clk_ipg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) fbi->clk_ahb = devm_clk_get(&pdev->dev, "ahb");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) if (IS_ERR(fbi->clk_ahb)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) ret = PTR_ERR(fbi->clk_ahb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) goto failed_getclock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) fbi->clk_per = devm_clk_get(&pdev->dev, "per");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) if (IS_ERR(fbi->clk_per)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) ret = PTR_ERR(fbi->clk_per);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) goto failed_getclock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) fbi->regs = ioremap(res->start, resource_size(res));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) if (fbi->regs == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) dev_err(&pdev->dev, "Cannot map frame buffer registers\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) goto failed_ioremap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) fbi->map_size = PAGE_ALIGN(info->fix.smem_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) info->screen_buffer = dma_alloc_wc(&pdev->dev, fbi->map_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) &fbi->map_dma, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) if (!info->screen_buffer) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) dev_err(&pdev->dev, "Failed to allocate video RAM\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) goto failed_map;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) info->fix.smem_start = fbi->map_dma;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) if (pdata && pdata->init) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) ret = pdata->init(fbi->pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) goto failed_platform_init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) INIT_LIST_HEAD(&info->modelist);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) for (i = 0; i < fbi->num_modes; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) fb_add_videomode(&fbi->mode[i].mode, &info->modelist);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) * This makes sure that our colour bitfield
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) * descriptors are correctly initialised.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) imxfb_check_var(&info->var, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) * For modes > 8bpp, the color map is bypassed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) * Therefore, 256 entries are enough.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) ret = fb_alloc_cmap(&info->cmap, 256, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) goto failed_cmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) imxfb_set_par(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) ret = register_framebuffer(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) dev_err(&pdev->dev, "failed to register framebuffer\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) goto failed_register;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) fbi->lcd_pwr = devm_regulator_get(&pdev->dev, "lcd");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) if (PTR_ERR(fbi->lcd_pwr) == -EPROBE_DEFER) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) ret = -EPROBE_DEFER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) goto failed_lcd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) lcd = devm_lcd_device_register(&pdev->dev, "imxfb-lcd", &pdev->dev, fbi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) &imxfb_lcd_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) if (IS_ERR(lcd)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) ret = PTR_ERR(lcd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) goto failed_lcd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) lcd->props.max_contrast = 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) imxfb_enable_controller(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) fbi->pdev = pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) failed_lcd:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) unregister_framebuffer(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) failed_register:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) fb_dealloc_cmap(&info->cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) failed_cmap:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) if (pdata && pdata->exit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) pdata->exit(fbi->pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) failed_platform_init:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) dma_free_wc(&pdev->dev, fbi->map_size, info->screen_buffer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) fbi->map_dma);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) failed_map:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) iounmap(fbi->regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) failed_ioremap:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) failed_getclock:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) release_mem_region(res->start, resource_size(res));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) failed_req:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) failed_of_parse:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) kfree(info->pseudo_palette);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) failed_init:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) framebuffer_release(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) static int imxfb_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) struct imx_fb_platform_data *pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) struct fb_info *info = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) struct imxfb_info *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) imxfb_disable_controller(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) unregister_framebuffer(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) fb_dealloc_cmap(&info->cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) pdata = dev_get_platdata(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) if (pdata && pdata->exit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) pdata->exit(fbi->pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) dma_free_wc(&pdev->dev, fbi->map_size, info->screen_buffer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) fbi->map_dma);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) iounmap(fbi->regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) release_mem_region(res->start, resource_size(res));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) kfree(info->pseudo_palette);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) framebuffer_release(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) static int __maybe_unused imxfb_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) struct fb_info *info = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) struct imxfb_info *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) imxfb_disable_controller(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) static int __maybe_unused imxfb_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) struct fb_info *info = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) struct imxfb_info *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) imxfb_enable_controller(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) static SIMPLE_DEV_PM_OPS(imxfb_pm_ops, imxfb_suspend, imxfb_resume);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) static struct platform_driver imxfb_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) .name = DRIVER_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) .of_match_table = imxfb_of_dev_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) .pm = &imxfb_pm_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) .probe = imxfb_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) .remove = imxfb_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) .id_table = imxfb_devtype,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) module_platform_driver(imxfb_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) MODULE_DESCRIPTION("Freescale i.MX framebuffer driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) MODULE_AUTHOR("Sascha Hauer, Pengutronix");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) MODULE_LICENSE("GPL");